除了/token开头的地址都拦截
@Configuration
public class InterceptorConfiguration extends WebMvcConfigurationSupport {
@Autowired
private TokenHandlerInterceptor tokenHandlerInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenHandlerInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/token/**");
super.addInterceptors(registry);
}
}
@Configuration
public class TokenHandlerInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(TokenHandlerInterceptor.class);
@Autowired
private JwtService jwtService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
boolean flag = jwtService.verificationToken(request);
if(!flag) {
responseMessage("token无效或过期", response);
}
return flag;
} catch (Exception e) {
responseMessage(e.getMessage(), response);
}
return false;
}
private void responseMessage(String message, HttpServletResponse response) {
try (
OutputStream os = response.getOutputStream();
) {
os.write(message.getBytes(StandardCharsets.UTF_8));
} catch (Exception e2) {
log.error("write message error:", e2);
}
}
}
public interface JwtService {
/**
* 申请token
* @param name 用户名
* @param secretKey 密匙
* @param time 有效期
* @return
*/
String tokenApply(String name, String secretKey, long time);
/**
* 验证token
* @param token
* @return
*/
boolean verificationToken(String token) throws Exception;
/**
* 验证token
* @param request
* @return
*/
boolean verificationToken(HttpServletRequest request) throws Exception;
/**
* 续期
* @param oldToken
* @param name 用户名
* @param time
* @return
*/
String renewal(String oldToken, String name, long time);
}
@Service
public class JwtServiceImpl implements JwtService {
private static final Logger log = LoggerFactory.getLogger(JwtServiceImpl.class);
@Value("${jwt.secret}")
private String jwtSecret;
@Autowired
private RedissonClient redisson;
// 默认过期时间30天
private long jwtDefaultExpire = 1000L * 60 * 60 * 24 * 30;
@Override
public String tokenApply(String name, String secretKey, long time) {
long expire = time < 1 ? jwtDefaultExpire:time;
String jwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
.setSubject("app")
.setIssuedAt(new Date())
//设置过期时间
.setExpiration(new Date(System.currentTimeMillis() + expire))
.claim("user", name)
.signWith(SignatureAlgorithm.HS256, jwtSecret)
.compact();
redisson.getBucket(secretKey).set(jwtToken);
redisson.getBucket(secretKey).expire(expire, TimeUnit.MILLISECONDS);
return jwtToken;
}
@Override
public boolean verificationToken(String token) throws Exception {
return checkToken(token);
}
@Override
public boolean verificationToken(HttpServletRequest request) throws Exception {
return checkToken(request.getHeader("secret_key"))
|| checkToken(request.getHeader("access_token"))
|| checkToken(request.getHeader("token"));
}
@Override
public String renewal(String secretKey, String name, long time) {
Object oldToken = redisson.getBucket(secretKey).get();
Assert.isTrue(null != oldToken, "请先申请密匙");
Claims claims = decryptToken(oldToken.toString());
if(null == claims) {
// token过期,直接重新申请
return tokenApply(name, secretKey, time);
}
return tokenApply(name,
secretKey,
claims.getExpiration().getTime() - System.currentTimeMillis() + (time < 1 ? jwtDefaultExpire:time));
}
private boolean checkToken(String secretKeys) throws Exception {
if(null == secretKeys) return false;
Object data = redisson.getBucket(secretKeys).get();
Assert.isTrue(null != data, "密匙不存在或者已过期");
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(data.toString());
} catch (ExpiredJwtException e) {
throw new Exception("密匙过期或无效");
}
return true;
}
private Claims decryptToken(String token) {
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return claimsJws.getBody();
} catch (ExpiredJwtException e) {
log.error("Jwts.parser error:", e);
}
return null;
}
}
@RestController
@RequestMapping("/token")
public class JwtTokenController {
@Autowired
private JwtService jwtService;
@Autowired
private RedissonClient redisson;
/**
* 密匙申请
* @param name 用户名
* @param time 有效期,毫秒值
* @return 返回密匙
*/
@PostMapping("/secretKeyApply")
public String secretKeyApply(@RequestParam String name, Long time) {
String secretKey = UUID.randomUUID().toString();
jwtService.tokenApply(name, secretKey, null == time ? -1:time.longValue());
return secretKey;
}
/**
* 续期
* @param secretKey 密匙
* @param name 用户名
* @param time 续期时间
* @return
*/
@PostMapping("/renewal")
public boolean renewal(@RequestParam String secretKey, @RequestParam String name, Long time) {
Assert.isTrue(null != secretKey, "密匙不能为空");
jwtService.renewal(secretKey, name, time);
return true;
}
/**
* 废除密匙
* @param secretKey
* @return
*/
@PostMapping("/abolish")
public boolean abolish(@RequestParam String secretKey) {
Assert.isTrue(null != secretKey, "密匙不能为空");
redisson.getBucket(secretKey).delete();
return true;
}
}
redis.address=127.0.0.1:6379
redis.password=密码
jwt.secret=随机字符串
至此jwt校验就完成了
@RestController
@RequestMapping("/test")
public class TestJwtController {
@PostMapping("/testjwt")
public String testJwt() {
return "verification token success";
}
}
直接访问:localhost:8080/test/testjwt 接口