在SpringBoot的依赖文件中,首先导入JJWT的依赖
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
创建一个工具类,实现Jwt的主要功能
在jwt中有三部分结构,表头、声明、加密算法
在JwtBuilder提供了在JWT规范中定义的标准注册权利要求名方便setter方法。他们是:
public String createJWTToken(Map<String,String> infoMap, long efftice_min_time) {
String jwtKey = "dsgsgcxvcx54s31gd3s2x3zvdsdev";
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//We will sign our JWT with our ApiKey secret
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtKey);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
Map<String, Object> claims = new HashMap<>(infoMap);
UUID uuid = UUID.randomUUID();
claims.put(Claims.ID,uuid);
//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setExpiration(tokenExpiration)
.signWith(signatureAlgorithm, signingKey);
// if(null != tokenExpiration) {
// builder.setExpiration(tokenExpiration);
// }
//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}
public static void verify(String token) {
Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(jwtKey))
.setAllowedClockSkewSeconds(10)
.parseClaimsJws(token)
.getBody();
}
根据代码中出现的异常,判断token状态。可能出现的异常:
用来标记 不用验证token的方法
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface PassToken {
boolean required() default true;
}
用来标记 需要验证token的方法
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
用来拦截收到的请求,判断是否需要对token进行验证。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
// 如果不是映射到方法,直接通过
if (! (handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//检查是否有 pass token 注释,如果有则跳过认真
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passTokenAnnotation = method.getAnnotation(PassToken.class);
if (passTokenAnnotation.required()) {
System.out.println("pass token");
return true;
}
}
// 检查是否有需要 用户权限 的注解
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginTokenAnnotation = method.getAnnotation(UserLoginToken.class);
if (userLoginTokenAnnotation.required()) {
if (token == null) {
throw new RuntimeException("no token info.");
}
// 只是简单打印结果,未做其他处理。##
String resToken = tokenUtils.verifyTokenDate(token);
System.out.println("user login token :\n");
System.out.println(resToken);
return true;
}
return true;
}
return true;
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@PassToken
@GetMapping("/login")
public String login() {
TokenUtils tokenUtils = new TokenUtils();
Map<String, String> paramMap = new HashMap<>();
paramMap.put("id", "11111111");
Date date = new Date();
Date afterDate = new Date(date.getTime() + 20000);
String jwtToken = tokenUtils.createJWTToken(paramMap, afterDate);
return jwtToken;
}
@GetMapping("/test")
@UserLoginToken
public void testToken(@PathParam("token") String token) {
tokenUtils.verifyTokenDate(token);
}
关于token的时效性问题,需要考虑重置 过期时间 的问题,查看了网上的一些方法,对这个问题的处理都绝不不是很完美…
参考文档1
参考文档2