基于jwt的token使用(jwt实现token登陆权限认证)
基于jwt的token使用(jwt实现token登陆权限认证)验证成功返回响应的资源给浏览器。否则异常处理每次手到客户端请求,服务器验证该jwt的token服务器接受到请求后使用私钥创建一个jwt,这边会生成token服务器返回这个jwt给浏览器浏览器需要将带有token的jwt放入请求头
一 前言
此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程;对小项目而已是个轻量级的认证机制,符合开发需求;更多精彩原创内容关注公主号知识追寻者,读者的肯定,就是对作者的创作的最大支持;
二 jwt实现登陆认证流程
用户使用账号和面发出post请求
服务器接受到请求后使用私钥创建一个jwt,这边会生成token
服务器返回这个jwt给浏览器
浏览器需要将带有token的jwt放入请求头
每次手到客户端请求,服务器验证该jwt的token
验证成功返回响应的资源给浏览器。否则异常处理
三 相关介绍jwt
3.1jwt 组成
JWT的token由三段信息构成的,将这三段信息文本用.连接一起就构成了JWT字符串;
Header 头部(包含了令牌的元数据,并且包含签名和或加密算法的类型)
Payload 负载
Signature 签名/签证
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1ODI4OTc4NDUsInVzZXJuYW1lIjoienN6eHoifQ.vyiExkFWCCmQA3PFYL0jJfIiYGWubngqB0WcgmtHOxg
1
3.2 jwt优点
简洁(Compact): 可以通过URL,POST参数或者在HTTP header发送,数据量小,传输速度快
自包含(Self-contained):负载中包含了所有用户所需要的信息,避免多次查询数据库
.因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言支持;
不需要在服务端保存会话信息,适用于分布式与微服务;
四 jwt用户登陆发放token
4.1 pom.xml
项目构件如下
springboot 2.1;
jwt 3.4.0;
maven 3.5
jdk1.8
postman接口测试
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
4.2jwt工具类
jwt工具类中有三个方法,分别是生成数字签名用于用户首次登陆时发送jwt给客户端;其次是校验方法,用于拦截器拦截所有规则内的url,每个请求都必须带有服务器发送的jwt,经过验证后才放行请求;最后一个获得用户名的方法用于查询密钥,在验证jwt时作为参数传入;
/* *
* @Author lsc
* <p> JWT工具类 </p>
* @Param
* @Return
*/
public class JwtUtil {
// Token过期时间30分钟
public static final long EXPIRE_TIME = 30 * 60 * 1000;
/* *
* @Author lsc
* <p> 校验token是否正确 </p>
* @Param token
* @Param username
* @Param secret
* @Return boolean
*/
public static boolean verify(String token String username String secret) {
try {
// 设置加密算法
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withClaim("username" username)
.build();
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception exception) {
return false;
}
}
/* *
* @Author lsc
* <p>生成签名 30min后过期 </p>
* @Param [username secret]
* @Return java.lang.String
*/
public static String sign(String username String secret) {
Date date = new Date(System.currentTimeMillis() EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username" username)
.withExpiresAt(date)
.sign(algorithm);
}
/* *
* @Author lsc
* <p> 获得用户名 </p>
* @Param [request]
* @Return java.lang.String
*/
public static String getUserNameByToken(HttpServletRequest request) {
String token = request.getHeader("token");
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username")
.asString();
}
}
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
4.3 用户实体
实体中包含用户名,和密码,一切从简;
/**
* @Author lsc
* <p> </p>
*/
@Data
public class SysUser {
private String username;
private String password;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
4.4Controller
表现层代码用户用户登陆认证,认证成功后发放token给客户端;
/**
* @Author lsc
* <p> </p>
*/
@RestController
public class SysUserController {
@PostMapping(value = "/login")
public Map<String Object> login(@RequestBody SysUser sysUser){
Map<String Object> map = new HashMap<>();
String username = sysUser.getUsername();
String password = sysUser.getPassword();
// 省略 账号密码验证
// 验证成功后发送token
String token = JwtUtil.sign(username password);
if (token != null){
map.put("code" "200");
map.put("message" "认证成功");
map.put("token" token);
return map;
}
map.put("code" "403");
map.put("message" "认证失败");
return map;
}
}
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
4.5 测试
测试url http://localhost:8080/login
postman post请求测试参数如下
{
"username": "zszxz"
"password": "zszxz"
}
1
2
3
4
返回内容如下
{
"code": "200"
"message": "认证成功"
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1ODI4OTc4NDUsInVzZXJuYW1lIjoienN6eHoifQ.vyiExkFWCCmQA3PFYL0jJfIiYGWubngqB0WcgmtHOxg"
}
1
2
3
4
5
五 jwt登陆拦截认证
基于前面已经实现jwt登录认证后发放token给客户端;本节内容就是将token放入请求头中发送请求给服务器;服务器使用拦截器拦截请求对token进行验证;验证成功请求通过,否则请求资源失败;
5.1自定义拦截器
自定义拦截器JwtInterceptor,实现HandlerInterceptor接口,每次请求到达之前都会验证token是否有效;
/**
* @Author lsc
* <p>token验证拦截器 </p>
*/
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
SysUserService sysUserService;
@Override
public boolean preHandle(HttpServletRequest request HttpServletResponse response Object handler) throws Exception {
// 从 http 请求头中取出 token
String token = request.getHeader("token");
// 如果不是映射到方法直接通过
if(!(handler instanceof HandlerMethod)){
return true;
}
if (token != null){
String username = JwtUtil.getUserNameByToken(request);
// 这边拿到的 用户名 应该去数据库查询获得密码,简略,步骤在service直接获取密码
boolean result = JwtUtil.verify(token username sysUserService.getPassword());
if(result){
System.out.println("通过拦截器");
return true;
}
}
return false;
}
@Override
public void postHandle(HttpServletRequest request HttpServletResponse response Object handler ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request HttpServletResponse response Object handler Exception ex) throws Exception {
}
}
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
5.2 service
/**
* @Author lsc
* <p> 模拟查询数据库获得账号密码 </p>
*/
@Service
public class SysUserService {
public String getPassword(){
return "zszxz";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
5.3拦截器配置
拦截器配置中主要定义拦截请求规则,将拦截器注入WebMvcConfigurer;cors跨域处理;
/* *
* @Author lsc
* <p>拦截器配置 </p>
* @Param
* @Return
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/* *
* @Author lsc
* <p> 设置拦截路径 </p>
* @Param [registry]
* @Return void
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
/* *
* @Author lsc
* <p> 将拦截器注入context </p>
* @Param []
* @Return com.zszxz.jwt.interceptor.JwtInterceptor
*/
@Bean
public JwtInterceptor authenticationInterceptor() {
return new JwtInterceptor();
}
/* *
* @Author lsc
* <p>跨域支持 </p>
* @Param [registry]
* @Return void
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET" "POST" "DELETE" "PUT" "PATCH" "OPTIONS" "HEAD")
.maxAge(3600 * 24);
}
}
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
5.4Controller
表现层接口用于拦截亲求测试
/**
* @Author lsc
* <p> </p>
*/
@RestController
public class TestController {
@GetMapping(value = "/api/test")
public String get(){
return "zszxz";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
5.5 测试
测试url http://localhost:8080/api/test
发送get请求给服务器,带有请求头 key为token value为用户首次登陆时返回的token串;
测试返回内容如下
zszxz
1
六 官网链接
https://jwt.io/introduction/
————————————————
作者:知识追寻者
原文链接:https://blog.csdn.net/youku1327/java/article/details/104564953