在用户和服务器之间建立认证状态是Web开发中常见的需求。Session
和JWT
(JSON Web Token)是两种常用的机制,但它们在工作原理、存储方式和安全性等方面存在差异。
JWT
是一种开放标准(RFC 7519),用于在网络上安全传输信息的简洁、自包含的方式。它通常被用于身份验证和授权机制。JWT
由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
JWT
的信息以及所使用的算法类型。JWT
官方规定了7个字段,可供使用: iss
(Issuer):签发者。sub
(Subject):主题。aud
(Audience):接收者。exp
(Expiration time):过期时间。nbf
(Not Before):生效时间。iat
(Issued At):签发时间。jti
(JWT ID):编号。相较于传统的基于会话(Session)的认证机制,JWT
具有以下优势:
JWT
中。JWT
可以轻松地在多个域之间进行传递和使用,实现跨域授权。JWT
包含了认证和授权信息,以及其他自定义的声明,这些信息都被编码在JWT
中。JWT
可以被扩展和定制,可以按照需求添加自定义的声明和数据。在Java开发中,可以借助JWT
工具类来方便的操作JWT
,例如HuTool框架中的JWTUtil
。
在pom.xml
中添加以下依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
Map<String, Object> map = new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put("uid", Integer.parseInt("123")); // 用户ID
put("expire_time", System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15); // 过期时间15天
}
};
String token = JWTUtil.createToken(map, "服务器端秘钥".getBytes());
验证Token
的示例代码如下:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MjQwMDQ4MjIsInVzZXJJZCI6MSwiYXV0aG9yaXRpZXMiOlsiUk9MRV_op5LoibLkuozlj7ciLCJzeXNfbWVudV8xIwiUk9MRV_op5LoibLkuIDlj7ciLCJzeXNfbWVudV8yIl0sImp0aSI6ImQ0YzVlYjgwLTA5ZTctNGU0ZC1hZTg3LTVkNGI5M2FhNmFiNiIsImNsaWVudF9pZCI6ImhhbmR5LXNob3AifQ.aixF1eKlAKS_k3ynFnStE7-IRGiD5YaqznvK2xEjBew";
JWTUtil.verify(token, "123456".getBytes());
解析Token
的示例代码如下:
String rightToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsIm5hbWUiOiJsb29seSJ9.U2aQkC2THYV9L0fTN-yBBI7gmo5xhmvMhATtu8v0zEA";
final JWT jwt = JWTUtil.parseToken(rightToken);
jwt.getHeader(JWTHeader.TYPE);
jwt.getPayload("sub");
在登录成功之后,生成Token
的示例代码如下:
// 登录成功,使用 JWT 生成 Token
Map<String, Object> payload = new HashMap<String, Object>() {
private static final long serialVersionUID = 1L;
{
put("uid", userinfo.getUid());
put("manager", userinfo.getManager());
// JWT 过期时间为 15 天
put("exp", System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15);
}
};
String token = JWTUtil.createToken(payload, AppVariable.JWT_KEY.getBytes());
例如在Spring Cloud Gateway网关中验证Token
的实现代码如下:
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.example.common.AppVariable;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 登录过滤器(登录判断)
*/
@Component
public class AuthFilter implements GlobalFilter, Ordered {
// 排除登录验证的 URL 地址
private String[] skipAuthUrls = {"/user/add", "/user/login"};
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 当前请求的 URL
String url = exchange.getRequest().getURI().getPath();
for (String item : skipAuthUrls) {
if (item.equals(url)) {
// 继续往下走
return chain.filter(exchange);
}
}
ServerHttpResponse response = exchange.getResponse();
// 登录判断
List<String> tokens =
exchange.getRequest().getHeaders().get(AppVariable.TOKEN_KEY);
if (tokens == null || tokens.size() == 0) {
// 当前未登录
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// token 有值
String token = tokens.get(0);
// JWT 效验 token 是否有效
boolean result = false;
try {
result = JWTUtil.verify(token, AppVariable.JWT_KEY.getBytes());
} catch (Exception e) {
result = false;
}
if (!result) {
// 无效 token
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
} else { // 判断 token 是否过期
final JWT jwt = JWTUtil.parseToken(token);
// 得到过期时间
Object expObj = jwt.getPayload("exp");
if (expObj == null) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
long exp = Long.parseLong(expObj.toString());
if (System.currentTimeMillis() > exp) {
// token 过期
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
// 值越小越早执行
return 1;
}
}
JWT
本质上是将秘钥存放在服务器端,并通过某种加密手段进行加密和验证的机制。加密签名=某加密算法(header+payload+服务器端私钥),因为服务端私钥别人不能获取,所以JWT
能保证自身其安全性。
Session
和JWT
的区别主要有以下几点:
Session
机制依赖于服务器端的存储,而JWT
是一种无状态的认证机制,它通过在客户端存储令牌(Token)来实现认证。Session
信息存储在服务器端,而JWT
信息存储在客户端。Session
的有效期通常由服务器控制,而JWT
的有效期可以在令牌生成时设置,并且可以在客户端进行缓存和重复使用。Session
和JWT
各有优势和适用场景。Session
适合于需要频繁更改用户状态和服务器资源充足的场景,而JWT
适合于分布式系统、微服务架构以及需要跨域认证的场景。选择合适的认证机制,可以提高系统的安全性、可扩展性和维护性。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有