SpringBoot 基于拦截器结合redis实现登录token校验

为什么要使用redis

1 redis本身就是一个缓存NOSQL(不仅仅是数据库)型数据库,存储一下json字符串
2  效率高查询速度极快
3 可以存储一些工程的常量以及一些基础数据    

为什么要使用token

1  提高了项目的安全性的问题,一般的项目会采用shiro或者spring security 进行权限校验。 这个问题导致了项目加载速度慢。这些东西也是基础HttpSession来进行存储数据的 比如shiro
2 token就是一串加密之后的字符串 。自己可以选择RSA加密,秘钥和私钥以及base64等等。。。    

##废话不多说,直接上代码

  • 自定义注解
  • 编写拦截器
  • 配置拦截器
  • 代码以及功能测试
1
2
3
4
5
6
项目添加pom redis dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>

在项目添加自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package template.mybatis.springboot.authorization.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在Controller的方法上使用此注解,该方法在映射时会检查用户是否登录,未登录返回401错误
* @author lwq
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {
}

Redis管理

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
package template.mybatis.springboot.authorization.manager.impl;
import template.mybatis.springboot.authorization.model.TokenModel;
/**
* 对Token进行操作的接口
* @author lwq
*/
public interface TokenManager {
/**
* 创建一个token关联上指定用户
* @param userId 指定用户的id
* @return 生成的token
*/
public TokenModel createToken(String userId);
/**
* 检查token是否有效
* @param model token
* @return 是否有效
*/
public boolean checkToken(String authorization);
/**
* 从字符串中解析token
* @param authentication 加密后的字符串
* @return
*/
public TokenModel getToken(String authentication);
/**
* 清除token
* @param userId 登录用户的id
*/
public void deleteToken(String authentication);
}
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package template.mybatis.springboot.authorization.manager.impl;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.xiaoleilu.hutool.crypto.SecureUtil;
import com.xiaoleilu.hutool.json.JSONUtil;
import lombok.Data;
import template.mybatis.springboot.authorization.model.TokenModel;
/**
*
* token redis Manager
*
*/
@Component
@Data
public class RedisTokenManager implements TokenManager{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public TokenModel createToken(String userId) {
String token = SecureUtil.simpleUUID();
TokenModel TokenModel=new TokenModel(userId, token);
String value = JSONUtil.toJsonStr(TokenModel);
redisTemplate.boundValueOps(token)
.set(value, template.mybatis.springboot.model.Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS); //一天过期时间
return TokenModel;
}
@Override
public boolean checkToken(String token) {
//
if(!(StringUtils.isEmpty(token))){
String json = redisTemplate.boundValueOps(token).get();
com.xiaoleilu.hutool.json.JSONObject parseObj = JSONUtil.parseObj(json);
TokenModel bean = parseObj.toBean(TokenModel.class);
if(token.equals(bean.getToken())){
//程序授权过期时间
return redisTemplate.boundValueOps(token) .expire(template.mybatis.springboot.model.Constants.TOKEN_EXPIRES_HOUR, TimeUnit.HOURS);
}
}
return false;
}
@Override
public TokenModel getToken(String authentication) {
//获取
String json = redisTemplate.boundValueOps(authentication).get();
// JSONUtil.
com.xiaoleilu.hutool.json.JSONObject parseObj = JSONUtil.parseObj(json);
TokenModel bean = parseObj.toBean(TokenModel.class);
return bean;
}
@Override
public void deleteToken(String authentication) {
redisTemplate.delete(authentication);
}
}
}
注释:@Data 采用了lombok 有兴趣的同学可以学习一下,本人觉得非常好呀。

编写拦截器

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package template.mybatis.springboot.authorization.interceptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.druid.util.StringUtils;
import template.mybatis.springboot.authorization.annotation.Authorization;
import template.mybatis.springboot.authorization.manager.impl.TokenManager;
/**
*
* 1,判断请求是否要权限认证
* 2.进行redis权限认证
*
*/
@Component
public class AuthorizationIntercetor extends HandlerInterceptorAdapter {
@Autowired
TokenManager redisTokenManager;
/**
* This implementation always returns {@code true}.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//映射的不是方法
if(!(handler instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod =(HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//得到该处理器是否需要认证
Authorization annotation = method.getAnnotation(Authorization.class);
if(annotation==null){
return true;
}else{
String authorization = request.getHeader(template.mybatis.springboot.model.Constants.AUTHORIZATION);
if(!StringUtils.isEmpty(authorization)){
boolean checkToken = redisTokenManager.checkToken(authorization);
if(checkToken){
return true;
}else{
returnJson(response, "授权失败");
}
}else{
returnJson(response, "该接口未认证或者未签名或者不存在此资源");
}
}
return true;
}
/**
* This implementation is empty.
*/
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
/**
* This implementation is empty.
*/
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
/**
* 异常返回
* @param response
* @param json
* @throws Exception
*/
private void returnJson(HttpServletResponse response, String json) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=utf-8");
try {
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null)
writer.close();
}
}
}

Controller 代码测试

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
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import template.mybatis.springboot.authorization.manager.impl.TokenManager;
import template.mybatis.springboot.authorization.model.TokenModel;
import template.mybatis.springboot.model.ResultModel;
import template.mybatis.springboot.model.UserInfo;
import template.mybatis.springboot.service.UserInfoService;
/**
* @author lwq
*/
@RestController
@RequestMapping("/users")
public class UserInfoController {
@Autowired
private UserInfoService userInfoService;
@Autowired
private TokenManager tokenManager;
/**
* 登录以及授权
*/
@ResponseBody
@RequestMapping("/login")
public ResponseEntity<ResultModel> login(@RequestBody Map<String, String> request ) {
UserInfo login = userInfoService.login(request.get("username"), request.get("password"));
if(login!=null){
TokenModel createToken = tokenManager.createToken(request.get("username"));
return ResultModel.success(createToken);
}else{
return ResultModel.fail(403, "用户名或密码错误");
}
}
}

结果返回success

1
2
3
4
5
6
7
8
9
{
"code": 100,
"message": "成功",
"data": {
"userId": "admin",
"token": "d99fd350c5d94231b017b6a9b1d4f089"
},
"total": 0
}

随时扣作者QQ:23 9549 9549

在线聊天作者