博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Boot JWT Token 认证 (JAVA WEB TOKEN)
阅读量:4131 次
发布时间:2019-05-25

本文共 8933 字,大约阅读时间需要 29 分钟。

Spring Boot REST 风格 API 接口 JWT Token 认证 (JAVA WEB TOKEN)

文章目录

需求分析

接口认证需求:

1 能够有选择地过滤没有权限(Token)的请求

2 Token 具有时效性
3 如果用户连续操作,Token 能够自动刷新(自动延长有效期)

核心依赖

com.auth0
java-jwt
3.8.3

本文使用目前最新版本的依赖

核心代码

JwtUtil 生成和解密Token

package com.example.util;import com.auth0.jwt.JWT;import com.auth0.jwt.JWTVerifier;import com.auth0.jwt.algorithms.Algorithm;import java.util.Date;/** * @Author: lty * @Date: 2019/12/17 09:33 */public class JwtUtil {
private final static String DEFAULT_SECRET = "TASDASDF9823K4JH29S8D2H349SDFH14"; //region 加密区 public static String encode(String k, String v) {
return encode(k, v, 0); } private static String encode(String k, String v, long expireTime) {
return encode(null, k, v, expireTime); } private static String encode(String secret, String k, String v, long expireTime) {
if (secret == null || secret.length() < 1) {
secret = DEFAULT_SECRET; } Date expDate = null; if (expireTime > 1) {
expDate = new Date(System.currentTimeMillis() + expireTime); } //创建加密的token Algorithm algorithm = Algorithm.HMAC256(secret); String token =JWT.create().withIssuer("lty").withClaim(k,v) .withExpiresAt(expDate).sign(algorithm); return token; } //endregion //region 解密区 public static String decode(String key, String encryptedToken) {
return decode(null, key, encryptedToken); } public static String decode(String secret, String key, String encryptedToken) {
if ("".equals(secret) || null == secret) {
secret = DEFAULT_SECRET; } Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("lty") .build(); String s = verifier.verify(encryptedToken).getClaim(key).asString(); return s; } //endregion public static void main(String[] args) {
String encode = JwtUtil.encode("TokenKey", "843328437@1576551621592"); System.out.println(encode); String lty = JwtUtil.decode("TokenKey", encode); System.out.println(lty); }}

Token 拦截器

拦截器配置

package com.example.interceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configurationpublic class InterceptorConfig extends WebMvcConfigurationSupport {
/** * 多个拦截器组成一个拦截器链 * addPathPatterns 用于添加拦截规则 * excludePathPatterns 用户排除拦截 * @param registry */ @Override protected void addInterceptors(InterceptorRegistry registry) {
//拦截 registry.addInterceptor(new TokenInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/autologon/authorizationLogin"); super.addInterceptors(registry); } /** * 配置静态资源映射 * @param registry */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) {
///将所有/static/** 访问都映射到classpath:/static/ 目录下 registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); super.addResourceHandlers(registry); }}
package com.example.interceptor;import com.example.pojo.Result;import com.example.util.JwtUtil;import com.example.util.ResultUtil;import com.fasterxml.jackson.databind.ObjectMapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.Date;import java.util.Objects;public class TokenInterceptor implements HandlerInterceptor {
private final Logger logger = LoggerFactory.getLogger(TokenInterceptor.class); private final String TOKEN_HEADERS_FIELD = "authCheckCode"; private final String TOKEN_KEY = "TokenKey"; public static final long TOKEN_REFRESH_TIME_MILLIS = 1000 * 60 * 60 * 2L; public static final long TOKEN_EXPIRE_TIME_MILLIS = 1000 * 60 * 60 * 24 * 30L; /** * controller 执行之前调用 * @param httpRequest * @param httpResponse * @param o * @return * @throws IOException */ @Override public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Object o) throws Exception {
httpResponse.addHeader("Access-Control-Allow-Origin", "*"); httpResponse.addHeader("Access-Control-Allow-Headers","*"); // 允许跨域的Http方法 httpResponse.addHeader("Access-Control-Allow-Methods", "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE"); // 允许浏览器访问 Token 认证响应头 httpResponse.addHeader("Access-Control-Expose-Headers", TOKEN_HEADERS_FIELD); // 默认返回原 Token httpResponse.setHeader(TOKEN_HEADERS_FIELD, httpRequest.getHeader(TOKEN_HEADERS_FIELD)); // 应对探针模式请求(OPTIONS) String methodOptions = "OPTIONS"; if (httpRequest.getMethod().equals(methodOptions)) {
httpResponse.setStatus(HttpServletResponse.SC_ACCEPTED); return true; } Result result = checkToken(httpRequest, httpResponse); if (!"00".equals(result.getCode())) {
logger.warn("{}",result.toString()); httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); httpResponse.setContentType("application/json; charset=utf-8"); httpResponse.setCharacterEncoding("utf-8"); PrintWriter writer = httpResponse.getWriter(); writer.write(new ObjectMapper().writeValueAsString(result.toString())); return false; } return true; } private Result checkToken(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
String token = request.getHeader(TOKEN_HEADERS_FIELD); if (token == null || token.length() < 1) {
return ResultUtil.requestFaild("无效请求头"); } String tokenValue = JwtUtil.decode(TOKEN_KEY, token); long time = Long.parseLong(tokenValue.substring(tokenValue.indexOf("@") + 1)); String user = tokenValue.substring(0, tokenValue.indexOf("@")); logger.info("{}, date: {}, user: {}", tokenValue, new Date(time), user); // 校验 Token 有效性 long subResult = System.currentTimeMillis() - time; if (subResult >= TOKEN_EXPIRE_TIME_MILLIS) {
return ResultUtil.requestFaild("Token过期"); } if (subResult > TOKEN_REFRESH_TIME_MILLIS) {
// 刷新 Token String newToken = JwtUtil.encode(TOKEN_KEY,user + "@" + System.currentTimeMillis()); System.out.println("生成新token "+ newToken+ "刷新时间 "+System.currentTimeMillis()); response.setHeader(TOKEN_HEADERS_FIELD, newToken); return ResultUtil.requestSuccess(null); } } catch (Exception e) {
logger.warn("Token 校验失败,{}:{}", e.getClass().getName(), e.getMessage()); return ResultUtil.requestFaild("Token验证失败"); } return ResultUtil.requestSuccess(null); } /** * controller 执行之后,且页面渲染之前调用 */ @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
} /* * * 页面渲染之后调用,一般用于资源清理操作 */ @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}}

测试

写一个HTTP接口 测试Token验证

/** * 功能描述   test * * @param * @return com.example.pojo.Result * @author lty * @date 2019/11/28 */@RequestMapping(value = "/t")public Result t() throws Exception {
return testService.testList();}

ers/tengyu/Library/Application Support/typora-user-images/image-20191217134325797.png)]

控制台输出日志

2019-12-17 13:43:46,095  INFO TokenInterceptor:78 - 843328437@1576551621592, date: Tue Dec 17 11:00:21 CST 2019, user: 843328437生成新token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJsdHkiLCJUb2tlbktleSI6Ijg0MzMyODQzN0AxNTc2NTYxNDI2MDk4In0.X-qsFfMAP9ebYIHjkpaD3rgJqqPp3QnTuek7aRKvEVE刷新时间 15765614261112019-12-17 13:43:46,113  INFO HttpAspect:50 - url=http://localhost:8080/example/test/t2019-12-17 13:43:46,113  INFO HttpAspect:52 - method=POST2019-12-17 13:43:46,114  INFO HttpAspect:54 - ip=0:0:0:0:0:0:0:12019-12-17 13:43:46,114  INFO HttpAspect:56 - class_method=com.example.controller.TestController.t2019-12-17 13:43:46,114  INFO HttpAspect:58 - args={}2019-12-17 13:43:46,114  INFO HttpAspect:59 - >>>>>>>>>>>>>>

Gtihub 地址: github.com/liangtengyu

公众号 java宝典

在这里插入图片描述

转载地址:http://zgbvi.baihongyu.com/

你可能感兴趣的文章
Vue 解决部署到服务器后或者build之后Element UI图标不显示问题(404错误)
查看>>
element-ui全局自定义主题
查看>>
facebook库runtime.js
查看>>
vue2.* 中 使用socket.io
查看>>
openlayers安装引用
查看>>
js报错显示subString/subStr is not a function
查看>>
高德地图js API实现鼠标悬浮于点标记时弹出信息窗体显示详情,点击点标记放大地图操作
查看>>
初始化VUE项目报错
查看>>
vue项目使用安装sass
查看>>
HTTP和HttpServletRequest 要点
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
关于无线PCB中 中50欧姆的特性阻抗的注意事项
查看>>
Spring的单例模式源码小窥
查看>>
后台服务的变慢排查思路(轻量级应用服务器中测试)
查看>>
MySQL中InnoDB事务的默认隔离级别测试
查看>>
微服务的注册与发现
查看>>
bash: service: command not found
查看>>
linux Crontab 使用 --定时任务
查看>>
shell编程----目录操作(文件夹)
查看>>
机器学习-----K近邻算法
查看>>