需求分析

后台管理系统中除了登录接口、获取验证码的接口在访问的时候不需要验证用户的登录状态,其余的接口在访问的时候都必须要求用户登录成功以后才可以进行访问。

登录过程
拦截器配置过程

拦截器配置说明

前端请求url 经过拦截器(放行登录和验证码)进行判断获取到token,从Redis中查询数据是否存在,
若数据存在放在ThreadLocal线程变量中,更新redis token存储的时间并放行
若不存在返回208状态码 返回前端页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.atguigu.spzx.common.util;

import com.atguigu.spzx.model.entity.system.SysUser;

public class AuthContextUtil {



// 创建一个ThreadLocal对象
private static final ThreadLocal<SysUser> threadLocal = new ThreadLocal<>() ;

// 定义存储数据的静态方法
public static void set(SysUser sysUser) {
threadLocal.set(sysUser);
}

// 定义获取数据的方法
public static SysUser get() {
return threadLocal.get() ;
}

// 删除数据的方法
public static void remove() {
threadLocal.remove();
}
}

拦截器Hander

UserAuthProperties 用于读取yml中的参数

1
2
3
4
5
6
7
8
@Data
@ConfigurationProperties(prefix = "spzx.auth")
public class UserAuthProperties {


private List<String> noAuthUrls;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@Component
public class LoginAuthInterceptor implements HandlerInterceptor {

@Autowired
RedisTemplate<String , String> redisTemplate;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//获取预检请求放行
String method = request.getMethod();
if("OPTIONS".equals(method)){
return true;
}
//取得token
String token = request.getHeader("token");
if(StrUtil.isEmpty(token))
{
responseNoLoginInfo(response) ;
return false ;
}
//得到用户json

String userInfoJSON = redisTemplate.opsForValue().get(CacheConstant.User_Login_Prefix + token);
if(StrUtil.isEmpty(userInfoJSON))
{
responseNoLoginInfo(response) ;
return false ;
}
//json存到threadLocal
SysUser sysUser = JSON.parseObject(userInfoJSON, SysUser.class);
AuthContextUtil.set(sysUser);
//重置redis

redisTemplate.expire(CacheConstant.User_Login_Prefix + token,30, TimeUnit.MINUTES);

return true;
}

private void responseNoLoginInfo(HttpServletResponse response) {
Result<Object> result = Result.build(null, ResultCodeEnum.LOGIN_AUTH);
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JSON.toJSONString(result));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) writer.close();
}
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
AuthContextUtil.remove();
}
}

配置拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
public class WebMvcConfiguration implements WebMvcConfigurer {

@Autowired
LoginAuthInterceptor loginAuthInterceptor;
@Autowired
UserAuthProperties userAuthProperties;

/***
*
*登录校验
**/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginAuthInterceptor)
.excludePathPatterns(userAuthProperties.getNoAuthUrls())
.addPathPatterns("/**");
}

/***
*
*CROS跨域
**/

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 添加路径规则
.allowCredentials(true) // 是否允许在跨域的情况下传递Cookie
.allowedOriginPatterns("*") // 允许请求来源的域规则
.allowedMethods("*")
.allowedHeaders("*") ; // 允许所有的请求头
}
}