说明
- 此演示的是前后端项目分离,所以存在跨域问题
- 登陆方式使用的是单点登陆,所以使用到redis
- redis中的key是token,value是用户对象
- 用户在一个项目登陆过则会生成token放入redis中,时效期一般是30分钟(可自定义),后端把此token返回给浏览器cookie中存储
- 单点登陆,可以一次登录后,在多个项目中无需再次登陆就可以默认是登录状态访问,因为多个项目共用一个redis,每个项目的登陆拦截器只要通过前端传过来的token在redis中查找是否有用户对象来判断是否放行即可,
定义登陆拦截器
- 因为是前后端分离的项目,在拦截器中,先放行跨域预请求,解决跨域问题
- 通过HandlerMethod对象,可以指定是否有贴在方法上的自定义登陆权限注解
- 通过前端传过来的token在redis中查找是否有用户对象,有则放行
public class CheckLoginInterceptor implements HandlerInterceptor {
@Autowired
private IUserInfoRedisService userInfoRedisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)){
return true;
}
String token = request.getHeader("token");
UserInfo user = userInfoRedisService.getUserByToken(token);
HandlerMethod hm = (HandlerMethod) handler;
if (hm.hasMethodAnnotation(RequireLogin.class)) {
if (user == null) {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(JSON.toJSONString(JsonResult.noLogin()));
return false;
}
}
return true;
}
}
配置拦截器
- 贴上@Configuration定义配置类,实现WebMvcConfigurer接口
- @Bean配合@Configuration使用,将拦截器交给spring管理
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Bean
public CheckLoginInterceptor checkLoginInterceptor(){
return new CheckLoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkLoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/users/checkPhone")
.excludePathPatterns("/users/sendVerifyCode")
.excludePathPatterns("/users/regist")
.excludePathPatterns("/users/login");
}