简介
上一篇文章讲了封装一个 JWT 的工具类在项目里去做用户的鉴权,但是存在一个问题就是,想要获取用户的信息,都得在控制层写一堆代码去获取请求头,然后再获取到 token,再从里面获取到用户的数据,比较的麻烦。所以得想个办法解决它。
一、基于拦截器的token与鉴权
对于上面提到的代码重复问题和权限控制问题,我们可以将这段代码放到拦截器中去实现。
二、Spring中的拦截器
Spring 为我们提供了org.springframework.web.servlet.handler.HandlerInterceptorAdapter 这个适配器,继承此类,可以非常方便的实现自己的拦截器。它有三个方法:分别实现预处理、后处理(调用了Service并返回ModelAndView,但未进行页面渲染)和返回处理(已经渲染了页面)
1.在 preHandle 中,可以进行编码、安全控制等处理;
2.在 postHandle 中,有机会修改 ModelAndView(如果有需要的话);
3.在 afterCompletion 中,可以根据ex是否为null判断是否发生了异常,进行日志记录。
三、在拦截器中实现用户鉴权
- 自定义拦截器类
@Component
public class JwtInterceptor extends HandlerInterceptorAdapter {
/**
* 简化获取token数据的代码编写(判断是否登录)
* 1.通过request获取请求token信息
* 2.从token中解析获取claims
* 3.将claims绑定到request域中
*/
@Autowired
private JwtUtils jwtUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.通过request获取请求token信息
String authorization = request.getHeader("Authorization");
//判断请求头信息是否为空,或者是否已Bearer开头
if(!StringUtils.isEmpty(authorization) && authorization.startsWith("Bearer")) {
//获取token数据
String token = authorization.replace("Bearer ","");
//解析token获取claims
Claims claims = jwtUtils.parseJwt(token);
//将当前claims绑定到request域
if(claims != null) {
request.setAttribute("user_claims", claims);
retuen true;
}
}
throw new CommonException(ResultCode.UNAUTHENTICATED);
}
}
- 修改之前的用户信息鉴权接口
/**
* 用户登录成功之后,获取用户信息
* 1.获取用户id
* 2.根据用户id查询用户
* 3.构建返回值对象
* 4.响应
*/
@PostMapping(value="/profile")
public Result profile(HttpServletRequest request) throws Exception {
//获取Claims
Claims claims = (Claims)request.getAttribute("user_claims");
//获取用户id
String userid = claims.getId();
//查询用户
User user = userService.findById(userid);
//构造用户信息响应体数据
ProfileResult result = new ProfileResult(user);
return new Result(ResultCode.SUCCESS,result);
}
四、配置拦截器类使自定义的拦截器生效
- 定义拦截器配置类
@Configuration
public class SystemConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtInterceptor jwtInterceptor;
/**
* 添加拦截器的配置
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//1.添加之前自定义拦截器
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**") //2.指定拦截器的url地址
.excludePathPatterns("/sys/login","/frame/register/**"); //3.指定不拦截的url地址
}
}