4. sa-token 鉴权框架
用户权限问题是一个系统不可缺少的部分,本项目采用sa-token框架。倒不是我给作者打广告哈,而是我觉得确实很好用,shiro太重了,我更倾向于选择sa-token,用我们国人自己的框架。
官网:Sa-Token
引入依赖:
<!-- Sa-Token 权限认证--> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.28.0</version> </dependency>
创建包
com.rabbit.diary.config
编写
SaTokenConfigure
@Configuration public class SaTokenConfigure implements WebMvcConfigurer { // 注册Sa-Token的注解拦截器,打开注解式鉴权功能 @Override public void addInterceptors(InterceptorRegistry registry) { // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关) registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); } }
写这个config是为了开启sa-token注解。
5. 用户接口和服务类
终于到用户接口编写啦,我们已经做了很多的准备工作,这个项目已经初步具备企业级工程化的标准了。很多企业小项目的架构杂乱无章,甚至都没有这么完备的体系。
用户服务类,我们采用接口+实现类的方式。
UserService
package com.rabbit.diary.service; import com.rabbit.diary.bean.User; import org.springframework.stereotype.Service; public interface UserService { User getByUserName(String userName); void save(User user); }
UserServiceImpl
package com.rabbit.diary.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.rabbit.diary.bean.User; import com.rabbit.diary.dao.UserMapper; import com.rabbit.diary.redis.RedisServiceImpl; import com.rabbit.diary.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.lang.annotation.Annotation; import java.util.List; @Service public class UserServiceImpl implements UserService { @Autowired UserMapper userMapper; @Autowired RedisServiceImpl redisServiceImpl; /** * 根据用户名获取用户 * @param userName * @return */ @Override public User getByUserName(String userName) { List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("user_name", userName)); if(users.size() > 0){ return users.get(0); } return null; } /** * 保存用户 * @param user */ @Override public void save(User user) { userMapper.insert(user); } }
很简单吧,就两个方法。
UserController:
package com.rabbit.diary.web; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.rabbit.diary.bean.User; import com.rabbit.diary.bean.core.BizException; import com.rabbit.diary.bean.core.ExceptionCodeEnum; import com.rabbit.diary.bean.core.Result; import com.rabbit.diary.redis.RedisServiceImpl; import com.rabbit.diary.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { @Autowired UserService userService; @Autowired RedisServiceImpl redisServiceImpl; String salt = "diary188"; @RequestMapping("register") public Result register(@RequestBody User user){ if(StrUtil.isEmpty(user.getUserName())){ throw new BizException(ExceptionCodeEnum.ERROR_PARAM.setDesc("用户名不允许为空!")); } if(StrUtil.isEmpty(user.getPassword())){ throw new BizException(ExceptionCodeEnum.ERROR_PARAM.setDesc("密码不允许为空!")); } //检查用户名是否重复 if(userService.getByUserName(user.getUserName()) != null){ throw new BizException(ExceptionCodeEnum.ERROR_PARAM.setDesc("用户名"+user.getUserName()+"重复!")); } //拼装userBean user.setUid(redisServiceImpl.getIncr("userId")); //redis自增ID user.setPassword(SecureUtil.md5(user.getPassword() + salt)); user.setCreateTime(DateUtil.now()); user.setUpdateTime(DateUtil.now()); userService.save(user); return Result.success(); } @RequestMapping("login") public Result login(@RequestBody User user){ User user1 = userService.getByUserName(user.getUserName()); if(user1 == null){ throw new BizException(ExceptionCodeEnum.ERROR_PARAM.setDesc("不存在的用户名:" + user.getUserName())); } String password = SecureUtil.md5(user.getPassword() + salt); if(!user1.getPassword().equals(password)){ throw new BizException(ExceptionCodeEnum.ERROR_PARAM.setDesc("账号和密码不匹配:" + user.getUserName())); } /**登录维持ID* */ StpUtil.login(user1.getUid(),"PC"); return Result.success(); } }
下面我们挑几个需要注意的点
01. 如何实现redis自增长ID?
user.setUid(redisServiceImpl.getIncr("userId")); //redis自增ID
02.如何保持登录ID?
StpUtil.login(user1.getUid(),"PC");
PageController
@Controller public class PageController { @RequestMapping("login") public String login(){ return "login"; } @RequestMapping("/") @SaCheckLogin public String index(){ return "index"; } }
注意,我们给index加上了saCheckLogin注解,这表示进入这个方法必须得是登录状态。
index.jsp是项目首页
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <c:set var="basePath" value="${pageContext.request.contextPath}"></c:set> <html> <head> <title>Title</title> <script src="${basePath}/layui/layui.all.js" charset="utf-8"></script> <link rel="stylesheet" href="${basePath}/layui/css/layui.css" media="all"> </head> <body> 首页 </body> </html>
启动项目,让我们访问:http://localhost/
看到:
{"code":"9999","message":"Token无效:3fd99f78-10aa-4690-bd83-5fae198d1b87","data":null}
这表示sa-token的配置已经生效了。
现在,我们去注册几个账号:
这就顺利进入了index.jsp。