首先简单回忆一下思路:登录接口为用户生成一个jwt,jwt存于redis中。在使用后续功能通过web拦截器拦截,先获取校验jwt是否过期,再决定是否放行。后续根据jwt中取出来的信息即可实现简单的鉴权
总体来说功能如下:本博客以springboot3+为例,使用jjwt0.12.3
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.12.3</version> </dependency>
1.JwtUtil,用于生成、解析jwt
public class JwtUtil { /** * 生成jwt * 使用Hs256算法, 私匙使用固定秘钥 * * @param secretKey jwt秘钥 * @param ttlMillis jwt过期时间(毫秒) * @param claims 设置的信息 * @return */ public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims) { //指定加密算法 SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256; //生成JWT的时间 long expMillis = System.currentTimeMillis()+ttlMillis; Date exp = new Date(expMillis); //密钥实例 SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes()); String compact = Jwts.builder() .signWith(key, algorithm) //设置签名使用的签名算法和签名使用的秘钥 //如果有私有声明,一点要先设置这个自己创建的私有的声明,这个是给builder的claims赋值,一旦卸载标准的声明赋值之后,就是覆盖了那些标准的声明的 .expiration(exp) .claims(claims) //设置自定义负载信息 .compact();//设置过期时间 return compact; } /** * Token解密 * * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个 * @param token 加密后的token * @return */ public static Jws<Claims> parseJWT(String secretKey, String token) { SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes()); Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token); return claimsJws; } }
2.登录接口,此处添加额外代码为用户设置jwt
//其他省略,这里只写如何为用户设置jwt,并将jwt传给前端,这里由于涉及了id和权限因此put了两个字段 UserDto userDto = new UserDto(); BeanUtils.copyProperties(user,userDto); Map<String,Object>claims=new HashMap<>(); claims.put("id",user.getId()); claims.put("status",user.getStatus()); String jwt = JwtUtil.createJWT(jwtContant.getSecretKey(), jwtContant.getTtl(), claims); userDto.setToken(jwt);
3.interceptor,拦截器,用于校验jwt信息。这里注意取值一定要和上述对应。
@Component @Slf4j public class JwtInterceptor implements HandlerInterceptor { @Autowired private JwtContant jwtContant; /** * 校验jwt * * @param request * @param response * @param handler * @return */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { //判断当前拦截到的是Controller的方法还是其他资源 if (!(handler instanceof HandlerMethod)) { //当前拦截到的不是动态方法,直接放行 return true; } //1、从请求头中获取令牌 String token = request.getHeader(jwtContant.getTokenName()); //2、校验令牌 try { log.info("jwt校验:{}", token); Jws<Claims> claimsJws = JwtUtil.parseJWT(jwtContant.getSecretKey(), token); Long userId = Long.valueOf(claimsJws.getPayload().get("id").toString()); Integer status = Integer.valueOf(claimsJws.getPayload().get("status").toString()); BaseContext.setCurrentId(userId); BaseContext.setCurrentStatus(status); log.info("当前角色id:{},访问权限是:{}", userId,status); //3、通过,放行 return true; } catch (Exception ex) { //4、不通过,响应401状态码 response.setStatus(401); return false; } } }
4.webmvcconfiguration,用于注册interceptor。这里设置一下不拦截登录和注册
@Configuration @Slf4j public class WebMvcConfig extends WebMvcConfigurationSupport { @Autowired JwtInterceptor jwtInterceptor; protected void addInterceptors(InterceptorRegistry registry) { log.info("加入jwt拦截器"); registry.addInterceptor(jwtInterceptor) .addPathPatterns("/**") .excludePathPatterns("/user/login","/user/register"); } }
5.设置一个上下文类,用于存储用户的信息,例如使用threadlocal
public class BaseContext { public static ThreadLocal<Long> threadLocal = new ThreadLocal<>(); public static ThreadLocal<Integer>threadLocal1=new ThreadLocal<>(); public static void setCurrentId(Long id) { threadLocal.set(id); } public static Long getCurrentId() { return threadLocal.get(); } public static void setCurrentStatus(Integer status) { threadLocal1.set(status); } public static Integer getCurrentStatus() { return threadLocal1.get(); } public static void removeCurrentId() { threadLocal.remove(); } }
6.后续取出BaseContext即可直接取出用户的信息、包括简单的鉴权
标签:指南,return,jwt,param,static,springboot3,claims,public From: https://www.cnblogs.com/kun1790051360/p/18673494