jwt的组成

json web token
定义了一种简洁的,自包含的格式,用于通信双方以json数据格式安全的传输信息

组成:

第一部分 Header(头) 纪录令牌类型,签名算法等
第二部分 Payload(有效载荷) 携带一些自定义信息,默认信息等
第三部分 Signature(签名) 防止token被篡改,确保安全性,将header,payload,并加入指定密钥,通过指定签名算法计算而来

认证流程

1.前端通过Web表单将自己的用户名和密码发送到后端的接口。该过程一般是HTTP的POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
2.后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。
3.后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage(浏览器本地缓存)或sessionStorage(session缓存)上,退出登录时前端删除保存的JWT即可。
4.前端在每次请求时将JWT放入HTTP的Header中的Authorization位。(解决XSS和XSRF问题)HEADER
5.后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确﹔检查Token是否过期;检查Token的接收方是否是自己(可选)
6·验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。
这是图片

编写jwt工具类

依赖导入

1
2
3
4
5
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.0</version>
</dependency>
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
package com.example.bigevent.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;

import java.util.Date;
import java.util.Map;

public class JwtUtil {
private static final String KEY ="itheima";
// 创建token的方法
// withClaim添加有效载荷(存放内容的地方,可添加多个)
// withExpiresAt设置有效时间
// sign设置签名防盗
public static String getToken(Map<String,Object> objectMap){
return JWT.create()
.withClaim("claim",objectMap).withExpiresAt(new Date(System.currentTimeMillis()+1000*60*60*12))
.sign(Algorithm.HMAC256(KEY));
}
// 验证token的方法
public static Map<String,Object> parseToken(String token){
return JWT.require(Algorithm.HMAC256(KEY)).build().verify(token).getClaim("claim").asMap();
}
}

登录界面创建token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RequestMapping("/login")
public Result login(@Pattern(regexp="^\\S{5,16}$")String username,@Pattern(regexp = "^\\S{5,16}$")String password){
User byUsername = userService.findByUsername(username);
if(byUsername==null){
return Result.error("用户不存在");
}else{
String ps = Md4Util.MD5(password);
System.out.println(ps);
System.out.println(byUsername.getPassword());
if (ps.equals(byUsername.getPassword())){
Map<String,Object> token = new HashMap<>();
token.put("username",byUsername.getUsername());
token.put("id",byUsername.getId());
String token1 = JwtUtil.getToken(token);
stringRedisTemplate.opsForValue().set(token1,token1,1, TimeUnit.HOURS);
return Result.success(token1);
}else{
return Result.error("密码错误");
}
}
}

与拦截器配合使用

编写拦截器类

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
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
System.out.println(token);
try {
Map<String, Object> claim = JwtUtil.parseToken(token);
System.out.println(claim);
ThreadLocalUtil.set(claim);
return true;
} catch (Exception e) {
response.setStatus(401);
return false;
}
}


@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
ThreadLocalUtil.remove();
}
}

编写ThreadLocalUtil管理数据减少多余代码

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
package com.example.bigevent.util;

import java.util.HashMap;
import java.util.Map;

/**
* ThreadLocal 工具类
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();

//根据键获取值
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}

//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}


//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}

配置拦截器

1
2
3
4
5
6
7
8
9
10
11

@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).excludePathPatterns("/user/login","user/register");
}
}