什么是JWT认证机制
Json Web Token(缩写JWT)是目前最流行的跨域认证解决方案
session登录的认证方案是看,用户从客户端传递用户名和密码登录信息,服务端认证后将信息储存在session中,将session_id放入cookie中,以后访问其他页面,服务器都会带着cookie,服务端会自动从cookie中获取session_id,在从session中获取认证信息。
JWT的解决方案是,将认证信息返回个客户端,储存在客户端,下次访问其他页面,需要从客户端传递认证信息回服务器端。
JWT结构
一个完整的Json Web Token将分为三个部分,header(头部)、payload (负载) 、signature (签名)。
头部 (header)
头部通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA。
例如:
{ "alg": "HS256", "typ": "JWT" }
然后,此JSON被 Base64Url 编码以形成JWT的第一部分。
有效载荷(payload)
令牌的第二部分是有效负载(payload),其中包含声明(claims)。声明是有关实体(通常是用户)和其他数据的声明。比如:registered, public, and private claims.
一个Payload的例子可以是
{ "sub": "1234567890", "name": "John Doe", "admin": true }
然后,对有效负载进行Base64Url编码,以形成JSON Web令牌的第二部分。
签名 (signature)
要创建签名部分,您必须获取编码的标头,编码的有效载荷,机密,标头中指定的算法,并对其进行签名。
例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
签名用于验证消息在整个验证过程中没有更改,并且如果使用私钥进行令牌的签名的,它还可以验证JWT的发件人是谁。
最后,一个完整的Token可以是下面这样

SpringBoot与JWT的整合
通过在SpringBoot中整合JWT,可以构建有认证机制的Restful Web服务,或者实现前后端分离开发中的状态认证(比如和Vue进行整合)。
导入相关Maven依赖
<!-- JWT Dependency--> <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
编写JWT的工具类
这里设置了每个Token的失效时间为1个小时以后,payload中存储了用户的uid和用户名等信息,tokenPassword为进行HMAC256签名的私钥,需要进行安全性的存储。
public class JwtUtil { private static final String tokenPassword = "your_secret_key"; public static String getToken(User user) { Instant dateTime = LocalDateTime.now().plusHours(1).toInstant(OffsetDateTime.now().getOffset()); Date expireTime = Date.from(dateTime); String token; token = JWT.create() .withClaim("uid", user.getId()) .withClaim("username", user.getUsername()) .withIssuedAt(new Date()) .withExpiresAt(expireTime) .sign(Algorithm.HMAC256(tokenPassword)); return token; } public static int verifyToken(String token) { JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenPassword)).build(); try { jwtVerifier.verify(token); } catch (TokenExpiredException e) { return Status.WARNING; } catch (JWTVerificationException e) { return Status.FORBIDDEN; } return Status.SUCCESS; } }
构建继承HandlerInterceptor的SpringBoot拦截器
@Component public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("Authorization").substring(7); int result = JwtUtil.verifyToken(token); if (result == Status.FORBIDDEN) { response.setStatus(401); return false; } else if (result == Status.WARNING) { request.setAttribute("tokenExpired", true); } request.setAttribute("tokenExpired", false); return true; } }
构建WebConfigurer类来注入拦截器
@Configuration public class WebConfigurer implements WebMvcConfigurer { UserInterceptor userInterceptor; public WebConfigurer(UserInterceptor userInterceptor) { this.userInterceptor = userInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(userInterceptor).addPathPatterns("/api/user/**"); } // 解决浏览器端跨站安全机制的问题 @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("Authorization"); } }
经过上述的操作,在对匹配的路径进行请求后,拦截器将会验证HTTP Headers中的Authorization头中的Token,并进行对应的传递或响应。
我的博客即将同步至腾讯云+社区,邀请大家一同入驻:
https://cloud.tencent.com/developer/support-plan?invite_code=1v5xqqcp1en4i
文章评论