什么是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。
例如:
代码语言:javascript复制{
"alg": "HS256",
"typ": "JWT"
}
然后,此JSON被 Base64Url 编码以形成JWT的第一部分。
有效载荷(payload)
令牌的第二部分是有效负载(payload),其中包含声明(claims)。声明是有关实体(通常是用户)和其他数据的声明。比如:registered, public, and private claims.
一个Payload的例子可以是
代码语言:javascript复制{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后,对有效负载进行Base64Url编码,以形成JSON Web令牌的第二部分。
签名 (signature)
要创建签名部分,您必须获取编码的标头,编码的有效载荷,机密,标头中指定的算法,并对其进行签名。
例如,如果要使用HMAC SHA256算法,则将通过以下方式创建签名:
代码语言:javascript复制HMACSHA256(
base64UrlEncode(header) "."
base64UrlEncode(payload),
secret)
签名用于验证消息在整个验证过程中没有更改,并且如果使用私钥进行令牌的签名的,它还可以验证JWT的发件人是谁。
最后,一个完整的Token可以是下面这样
SpringBoot与JWT的整合
通过在SpringBoot中整合JWT,可以构建有认证机制的Restful Web服务,或者实现前后端分离开发中的状态认证(比如和Vue进行整合)。
导入相关Maven依赖
代码语言:javascript复制 <!-- 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签名的私钥,需要进行安全性的存储。
代码语言:javascript复制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拦截器
代码语言:javascript复制@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类来注入拦截器
代码语言:javascript复制@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