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"; 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)); } 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 {
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;
@SuppressWarnings("all") public class ThreadLocalUtil { 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); }
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"); } }
|