Java中JWT令牌实现登录验证
1.实现登录验证的引出
传统思路下:
- 登录页面把用户名和密码交给服务器。
- 服务器验证用户名和密码是否正确,并返回校验结果给后端。
- 如果密码正确,就会在服务器创建Session,通过Cookie把sessionId返回给客户端。
原因
但是在集群环境下,无法直接使用Session。因为如果只部署在一台机器时,容易发生单点故障(一旦这台服务器挂了,整个应用就无法访问),所以通常情况下,一个Web应用会部署在多个服务器上,通过Nginx等进行负载均衡。此时,来自一个用户的请求就会分发到不同的服务器上。
- 使用Session时:
用户登录: 用户登录请求,经过负载均衡发送给服务器1,服务器1进行用户名和密码验证,验证成功后,把Session存在了服务器1上。
查询操作:用户登录之后,携带Cookie(里面带有SessionId)继续执行查询操作,假如进行查询博客列表,此时请求经过负载均衡发到服务器2上,服务器2会先通过SessionId验证用户是否登录,此时第二台机器上没有该用户的Session,即出现查询不了的问题。
2.JWT令牌
JWT全称:JSON Web Token,用于客户端和服务器之间传递安全可靠的信息,本质是一个token,也叫token,令牌的本质就是一个字符串。相当于现在人们的身份证,出门在外验证身份的时候,拿出身份证即可。
2.1 使用JWT令牌时
- 用户登录 : 用户登录请求,经过负载均衡,把请求发给服务器1,服务器1进行账号密码验证,验证成功之后,生成一个令牌,并返回给客户端。
- 客户端收到令牌时,把令牌存储起来,可以存储在Cookie中,也可以存储在其它的存储空间,典型的如(localStorage)
- 查询操作 用户登录之后,携带令牌继续执行查询操作,假如查询博客列表,此时请求经过负载均衡发到服务器2,服务器2先进行权限验证操作。服务器验证令牌是否有效,如果有效,说明用户已经执行了登录操作,如果无效,说明用户之前未执行登录操作。
2.2 令牌的组成
令牌官网所示,token,本质上一个字符串中间使用 符号 点 . 来分割,令牌由三部分组成,header、payload和verify signature。
第一部分:Header(头),令牌的类型和使用的签名算法,如"alg": “HS256(哈希算法)”, “typ”: “JWT”。
第二部分:Payload(负载),存放一些有效的信息(自定义信息,默认信息)如{“id”:“1”,“username”:“zhangsan”},还存在JWT提供的现场字段,如过期时间戳等。
第三部分:Signature(签名),防止token被篡改,确保安全性。
签名的目的就是为了防止token被篡改,而正因为token最后一个部分签名存在, 所以整个token是非常安全可靠的,一旦token当中的任何一部分被修改, 整个token在校验的时候都会失败。
3. JWT令牌(token)生成和校验
3.1 引入JWT令牌的依赖
- 在pom.xml文件中引入依赖
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --> <version>0.11.5</version> <scope>runtime</scope> </dependency>
3.2 使用Jar包中提供的API来实现JWT令牌的生成和校验
- 生成token之后,获取token进行解析,创建解释器,设置签名密钥,如果解析token的claims内容不为null,说明校验成功,否则失败。
package com.example.blog.utils; import com.example.blog.constant.Constants; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; import javax.crypto.SecretKey; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; @Slf4j public class JwtUtils { // JWT过期时间 public static final long JWT_EXPIRATION = 60*60*60*1000; // 生成key private static final String secretStr = "DuJXRS2W3AJHqyFhAplBmsPNawnEdFYFNmlNdMbyU9w="; private static final Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretStr)); /** * 生成token */ public static String genJwtToken(Map<String,Object> claim) { String token = Jwts.builder().setClaims(claim) .setExpiration(new Date(System.currentTimeMillis()+JWT_EXPIRATION)) .signWith(key) .compact(); return token; } /** * 校验token * Claims 为空,表示jwt校验失败 * */ public static Claims parseToken(String token) { // 创建解析器,设置签名密钥 JwtParser build = Jwts.parserBuilder().setSigningKey(key).build(); Claims claims = null; try { // 解析token claims = build.parseClaimsJws(token).getBody(); }catch (Exception e){ log.error("解析token失败,token:{}",token); return null; } return claims; } }
3.3 使用JWT令牌验证登录
3.4 令牌的优缺点
- 优点:
- 解决了集群环境下认证的问题
- 不需要在服务器端存储,从而减轻了服务器的存储压力
- 缺点:
- 需要自己实现令牌的生成、传递、校验
到此这篇关于Java中JWT令牌实现登录验证的文章就介绍到这了,更多相关Java JWT令牌登录验证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Java 中的 Class.forName(类名) 使用及原理解析
Class.forName是Java中用于动态加载类的强大工具,广泛应用于数据库驱动加载、反射机制和插件系统等场景,它通过ClassLoader加载类并执行静态初始化代码,但在使用时需要注意类路径、初始化副作用和类加载器的选择等问题,感兴趣的朋友一起看看吧2024-12-12
最新评论