网站首页 > java教程 正文
JSON Web 令牌(JWT)是一种开放标准(RFC 7519) ,它定义了一种紧凑和自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。可以验证和信任此信息,因为它是数字签名的。JWTs 可以使用 secret (使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
通俗的解释:JWT简称 JSON Web Token,也就是JSON形式作为Web应用中的令牌信息,用于在各方之间安全的将信息作为JSON对象传输,在数据传输过程中可以完成数据加密,签名等操作。
session认证
我们最先接触到的认证方式就是基于Session的认证方式,每一个会话在服务端都会存储在HttpSession中,相当于一个Map,然后通过Cookie的形式给客户端返回一个jsessionid,然后每次访问的时候都需要从HttpSession中根据jsessionid来获取,通过这个逻辑来判断是否是认证的状态。
Session认证虽然是常见且有效的身份验证和会话管理机制,但也存在一些潜在的弊端问题:
- 服务器端存储开销:每个活跃会话都需要在服务器端存储会话数据,这可能会占用服务器资源,特别是在用户量较大或会话数据较大的情况下会造成OOM。
- 扩展性问题:随着用户量的增加,服务器端会话存储的管理和扩展可能变得复杂。需要考虑如何处理负载均衡、高可用性和容错等问题。
- 会话劫持风险:如果会话标识符未经充分保护,攻击者可能会通过各种手段(如会话劫持、会话固定攻击)获取合法用户的会话,从而冒充用户。
- 跨站点请求伪造(CSRF)攻击:虽然Session认证本身不直接防止CSRF攻击,但可以结合其他技术(如CSRF Token)来增强安全性。如果未正确实施,会增加应用程序的安全风险。
- 会话管理复杂性:管理会话的过期、续期和注销过程可能会变得复杂,尤其是在多个设备和会话的情况下。
- 移动设备和API的兼容性:对于移动设备和API,通常需要额外的考虑,以确保会话管理的安全性和效率。
- 单点故障:如果会话存储在单个服务器或单个数据中心,并且该服务器或数据中心发生故障,则可能导致所有用户的会话失效或不可用。
基于JWT的认证
认证的流程:
- 用户通过表单把账号密码提交到后端服务后,如果认证成功就会生成一个对应的Token信息
- 之后用户请求资源都会携带这个Token值,后端获取到后校验通过放行,校验不通过拒绝
jwt的优势:
- 简介:可以通过URL,POST参数或者HTTP header发送,因为数据量小,传输速度快。
- 自包含:负载中包含了所有用户所需的信息,避免多次查询数据
- 夸语音:以JSON形式保存在客户端。
- 不需要服务端保存信息,适合分布式环境。
jwt组成
jwt令牌的组成:
- 标头(Header)
- 有效载荷(Payload)
- 签名(Signature)
因此JWT的格式为: xxxx.yyyy.zzzz Header.Payload.Signature
Header:
header通常由两部分组成:令牌的类型【JWT】和所使用的签名算法。例如HMAC、SHA256或者RSA,它会使用 Base64 编码组成 JWT结构的第一部分。注意:Base64是一种编码,是可以被翻译回原来的样子的。
{
"alg":"HS256",
"typ":"JWT"
}
Payload:
令牌的第二部分是有效负载,其中包含声明,声明是有关实体(通常是用户信息)和其他数据的声明,它会使用Base64来编码,组成JWT结构的第二部分。
{
"userId":"123444",
"userName":"yulang",
"admin":true
}
注意:载体中的数据只是进行了base64编码,所以在使用的时候需要注意下不用存放敏感的数据。
Signature:
签名部分,前面两部分都是使用 Base64 进行编码的,即前端可以解开header和payload中的信息,Signature需要使用编码后的 header 和 payload 以及我们提供的一个秘钥,然后使用 header 中指定的前面算法(HS256) 进行签名,签名的作用是保证 JWT 没有被篡改过
代码实现:
/**
* 生成Token信息
*/
public static String createToken(String userId) {
// 使用 HMAC SHA-256 算法生成密钥
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String jws = Jwts.builder()
.setSubject("yulang-token")
.claim("userId", userId)
.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时后过期
.signWith(key)
.compact();
return jws;
}
根据Token来验证是否正确。
public static String parseToken(String token) {
// 使用 HMAC SHA-256 算法生成密钥
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
System.out.println("Subject: " + claims.getSubject());
System.out.println("Expiration: " + claims.getExpiration());
return claims.get("userId")+ "";
}
要让拦截器生效我们还需要添加对应的配置类。
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/queryUser") // 需要拦截的请求
.addPathPatterns("/saveUser") // 需要拦截的请求
.excludePathPatterns("/login"); // 需要排除的请求
}
}
登录使用:
@PostMapping
public String login(@RequestBody @Validated LoginDTO loginDTO) {
// 业务操作 校验用户 密码
User user = new User();
user.setUserName(loginDTO.getUsername());
user.setUserId("11000");
String token = TokenUtil.createToken(user.getUserId());
stringRedisTemplate.opsForValue().set(user.getUserId(), JSONUtil.toJsonStr(user));
return token;
}
验证
验证获取登录后的数据:
@GetMapping("/index")
public User index() {
// 业务操作 校验用户 密码
return UserInfoHolderUtil.get();
}
猜你喜欢
- 2025-04-26 DuckDuckGo应用和扩展全面禁止谷歌的单点登录弹窗
- 2025-04-26 单点登录的终级解决方案-xxlSso
- 2025-04-26 单点登录(SSO)原理大揭秘:大龄程序员的硬核解析,看完秒懂!
- 2025-04-26 到底什么是单点登录(SSO)?
- 2025-04-26 带你全面了解 OAuth2.0
- 2025-04-26 单点登录和统一认证有区别吗
- 2025-04-26 单点登录解决方案 CAS(Central Authentication Service)详解
- 2025-04-26 JWT与OAuth2结合打造高效的单点登录系统
- 2025-04-26 统一认证及单点登录解决方案
- 2025-04-26 【免费开源】JeecgBoot单点登录源码全部开源了
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)