JWT快速入门
一、概念
JWT 可翻译为 JSON WEB TOKEN
###使用场景###
1、认证授权 (Authorization) :这是使用 JWT 的最常见场景。一旦用户登录,后续每个请求都将包含
JWT,允许用户访问该 Token 允许的路由、服务和资源。单点登录是现在广泛使用的 JWT 的一个特性,因为
它的开销很小,而且可以轻松地跨域使用。
2、信息交换 (Information Exchange) :对于安全的在各方之间传输信息而言,JSON Web Token 无疑
是一种很好的方式。因为 JWT 可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。
另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。
二、JWT与OAuth2.0
JWT 和 OAuth 2.0 是两个不同的概念。
JWT 是一种 JSON Web 令牌,它是使用 JSON 编码的声明,可以安全地在双方之间传输。JWT 可以用于身份验证、授权和信息交换。
OAuth 2.0 是一种授权框架,它允许用户授权第三方应用程序访问他们的资源。OAuth 2.0 可以用于各种用途,例如社交登录、单点登录和 API 访问。
JWT 和 OAuth 2.0 可以一起使用,以提供安全的身份验证和授权机制。例如,一个应用程序可以使用 OAuth 2.0 授权用户访问其 API,
然后使用 JWT 在用户之间安全地传输令牌。
以下是 JWT 和 OAuth 2.0 之间的一些关键区别:
* JWT 是一种声明,而 OAuth 2.0 是一种授权框架。
* JWT 可以使用 JSON 编码,而 OAuth 2.0 使用 HTTP 状态码和授权码。
* JWT 可以用于身份验证、授权和信息交换,而 OAuth 2.0 仅用于授权。
* JWT 可以由任何人创建,而 OAuth 2.0 需要使用 OAuth 2.0 授权服务器。
总体而言,JWT 和 OAuth 2.0 是两个不同的概念,但它们可以一起使用以提供安全的身份验证和授权机制。
三、无状态WEB服务 和 有状态WEB服务
1、有状态服务
有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。
例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,
用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。
缺点是什么?
服务端保存大量数据,增加服务端压力
服务端保存用户状态,无法进行水平扩展
客户端请求依赖服务端,多次请求必须访问同一台服务器
2、无状态服务
服务器不需要记录客户端的状态信息,即:
服务端不保存任何客户端请求者信息
客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份
带来的好处是什么呢?
客户端请求不依赖服务端的信息,任何多次请求不需要必须访问到同一台服务
服务端的集群和状态对客户端透明
服务端可以任意的迁移和伸缩
减小服务端存储压力
3、无状态服务实现
无状态登录的流程:
当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
以后每次请求,客户端都携带认证的token
服务的对token进行解密,判断是否有效。
这种基于 Token 的认证方式相比较于基于传统的 cookie 和 session 方式更加节约资源,并且对移动端和分布式系统支持更加友好,其优点有:
·支持跨域访问:cookie 是不支持跨域的,而 Token 可以放在请求头中传输
·无状态:Token 自身包含了用户登录的信息,无需在服务器端存储 session
·移动端支持更好:当客户端不是浏览器时,cookie 不被支持,采用 Token 无疑更好
·无需考虑 CRSF:不使用 cookie,也就无需考虑 CRSF 的防御
4、【整个登录过程中,最关键的点是什么?】
token的安全性
token是识别客户端身份的唯一标示,如果加密不够严密,被人伪造那就完蛋了。
采用何种方式加密才是安全可靠的呢?
我们将采用:JWT + RSA非对称加密
四、JWT结构
JWT 由三部分组成,分别是 Header(头部)、Payload(有效载荷)、Signature(签名),用点(.)将三部分隔开便是 JWT 的结构。
形如xxxxx.yyyyyy.zzzzz的字符串
【前两部分需要经过 Base64 编码】
【后一部分通过前两部分 Base64 编码后再加密而成】
1、Header(头部)
第一部分:Header,Header通常由【令牌的类型】和【加密的算法】组成,也就是
{
"alg": "HS256", ##算法
"typ": "JWT" ##类型
}
最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
默认内容:"alg":"HS256"
2、Payload(荷载)
payload 是 JWT 的主体部分,就是存放有效信息的地方(保存用户主体信息),每一个字段就是一个 claim(声明)
官方推荐声明【不强制使用,可自行定义】:
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
将该 json 字符串进行 Base64 编码得到:eyJpZCI6IjEyMzQ1NiIsIm5hbWUiOiJNb29ubGlnaHRMIiwic2V4IjoibWFsZSJ9(第二部分)。
3、Signature签名
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,
使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
真实情况,一般是在请求头里加入Authorization,并加上Bearer标注最后是JWT(格式:Authorization: Bearer <token>):
五、JWT的几个特点
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,
或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,
JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
六、简单入门
<!--JWT(Json Web Token)登录支持-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
生成jwt
@Test
public void generateJwt() {
//header头部信息---//不写header的话 默认内容为==>"alg":"HS256"
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
//payload荷载
Map<String, Object> payload = new HashMap<>();
payload.put("sub", "1234567890");
payload.put("username", "Ren");
payload.put("admin", true);
//申明token失效时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 300);//300s
//生成Token
String token = Jwts.builder()
.setHeader(header)//设置头部
.addClaims(payload)//设置荷载
.setExpiration(instance.getTime())//设置过期时间
.signWith(SignatureAlgorithm.HS256, "siyaomishi")//设置自己的私钥密匙
.compact();//压缩生成xxx.xxx.xxx
log.info(token);
//生成了三次,发现每次生成的header是相同的,payload和signature每次都不相同
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
//eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsInVzZXJuYW1lIjoiUmVuIiwiZXhwIjoxNzAyODgxNzY0fQ.
//uW6ISO9lRHzZQs9LqjOyCqx3Od4IJQCg7c5oc9bNb8c
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
//eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsInVzZXJuYW1lIjoiUmVuIiwiZXhwIjoxNzAyODgxNzkxfQ.
//B7lYTi4z24JlgmES44u49hFkQFhs5BVydi_U3kzk1W8
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
//eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsInVzZXJuYW1lIjoiUmVuIiwiZXhwIjoxNzAyODgxODg2fQ.
//JNg-1zPv0J5nE7maPIEmAzMmSA-Cq_KiEdCbLvUvzRc
}
通过
进行解码
解码JWT
/**
* 解析jwt
*/
@Test
public void decodeJwt() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiYWRtaW4iOnRydWUsInVzZXJuYW1lIjoiUmVuIiwiZXhwIjoxNzAyODgzMjEwfQ.pX7BZQkJd0NnMGePuDD7zoOBg0eMwuhLTmPQ0LrP0KE";
//解析header信息
JwsHeader header = Jwts.parser()
.setSigningKey("siyaomishi")//私钥密匙(签名算法的盐值key)
.parseClaimsJws(token)
.getHeader();
log.info("header:{}", JSON.toJSONString(header));
log.info("alg:{}", header.get("alg"));
log.info("typ:{}", header.get("typ"));
//解析荷载payload信息
Claims payload = Jwts.parser()
.setSigningKey("siyaomishi")//私钥密匙(签名算法的盐值key)
.parseClaimsJws(token)
.getBody();
log.info("payload:{}", JSON.toJSONString(payload));
log.info("sub:{}", payload.get("sub"));
log.info("username:{}", payload.get("username"));
log.info("admin:{}", payload.get("admin"));
//解析签名signature信息
String signature = Jwts.parser()
.setSigningKey("siyaomishi")//私钥密匙(签名算法的盐值key)
.parseClaimsJws(token)
.getSignature();
log.info("signature:{}", JSON.toJSONString(signature));
}
通过公钥、私钥来进行认证
/**
* 根据私钥生成token
*
* @param userDetails
* @param privateKey
* @return
*/
public String generateRsaToken(UserDetails userDetails, PrivateKey privateKey) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.RS256, privateKey).compact();
}
/**
* 根据公钥解析token
* @param token
* @param publicKey
* @return
*/
public Claims getClaimsFromRsaToken(String token, PublicKey publicKey) {
return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
}
/**
* 从文件中读取公钥
*
* @param filename 公钥保存路径,相对于classpath
* @return PublicKey 公钥对象
* @throws Exception
*/
public static PublicKey getPublicKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPublicKey(bytes);
}
/**
* 从文件中读取密钥
*
* @param filename 私钥保存路径,相对于classpath
* @return PrivateKey 私钥对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPrivateKey(bytes);
}
/**
* 获取公钥
* 公钥的字节形式。
*
* @param bytes 公钥的字节形式
* @return
* @throws Exception
*/
private static PublicKey getPublicKey(byte[] bytes) throws Exception {
bytes = Base64.getDecoder().decode(bytes);
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
/**
* 获取密钥
*
* @param bytes 私钥的字节形式
* @return
* @throws Exception
*/
private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
bytes = Base64.getDecoder().decode(bytes);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
/**
* 读文件
* @param fileName
* @return
* @throws Exception
*/
private static byte[] readFile(String fileName) throws Exception {
return Files.readAllBytes(new File(fileName).toPath());
}
/**
* 写文件
* @param destPath
* @param bytes
* @throws IOException
*/
private static void writeFile(String destPath, byte[] bytes) throws IOException {
File dest = new File(destPath);
if (!dest.exists()) {
dest.createNewFile();
}
Files.write(dest.toPath(), bytes);
}
/**
* 生成 公钥+私钥
*/
public static void main(String[] args) throws Exception {
String secret = "mysecret";//生成密钥的密文
int keySize = 1024;//密钥长度
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
//获取公钥
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);
log.info("publicKeyBytes:{}", new String(publicKeyBytes));
String rsaPubPath = ResourceUtils.getFile("classpath:rsa/id_rsa_pub").getPath();
log.info("rsaPubPath:{}", rsaPubPath);
writeFile(rsaPubPath, publicKeyBytes);
//获取私钥
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);
log.info("privateKeyBytes:{}", new String(privateKeyBytes));
String rsaPrivPath = ResourceUtils.getFile("classpath:rsa/id_rsa").getPath();
log.info("rsaPrivPath:{}", rsaPrivPath);
writeFile(rsaPrivPath, privateKeyBytes);
//根据私钥生成token
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("admin");
authorities.add(authority);
User userDetails = new User("lee","admin123",authorities);
PrivateKey privateKey = getPrivateKey(rsaPrivPath);
JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
String token = jwtTokenUtil.generateRsaToken(userDetails, privateKey);
log.info("token:{}",token);
//根据公钥解析token
PublicKey publicKey = getPublicKey(rsaPubPath);
Claims claims = jwtTokenUtil.getClaimsFromRsaToken(token, publicKey);
log.info("claims:{}", JSON.toJSONString(claims));
}
七、封装工具类
package com.lee.security.jwt;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.util.StringUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
/**
* @author Lee
* @version 1.0
* @description
* @date 2023-12-18 15:21
*/
@Slf4j
public class JwtTokenUtil {
//主体
private static final String CLAIM_KEY_USERNAME = "sub";
//创建时间
private static final String CLAIM_KEY_CREATED = "created";
//密钥长度 for RSA256
private static final int DEFAULT_KEY_SIZE = 2048;
@Value("${jwt.secret:siyaomishi}")
private String secret;
@Value("${jwt.expiration:604800}")
private Long expiration;
@Value("${jwt.tokenHead:'Bearer '}")
private String tokenHead;
//================HS256==================
/**
* 根据用户信息生成token
*
* @param userDetails 数据库中查询出来的用户信息
* @return
*/
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
/**
* 刷新token
*
* @param oldToken
* @return
*/
public String refreshHeadToken(String oldToken) {
if (StringUtil.isBlank(oldToken)) {
return null;
}
String token = oldToken.substring(tokenHead.length());
if (StringUtil.isBlank(token)) {
return null;
}
//token校验
Claims claims = getClaimsFromToken(token);
if (claims == null) {
return null;
}
//token过期,不支持刷新
if (isTokenExpire(token)) {
return null;
}
//token在30分钟之内刷新过,返回原token
if (tokenRefreshJustBefore(token, 30 * 60)) {
return token;
} else {
//生成新的token
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
}
/**
* 判断token是否在指定时间内刷新过
*
* @param token 原token
* @param time 指定时间s
* @return
*/
private boolean tokenRefreshJustBefore(String token, int time) {
Claims claim = getClaimsFromToken(token);
Date created = claim.get(CLAIM_KEY_CREATED, Date.class);
Date refreshDate = new Date();
if (refreshDate.after(created) && refreshDate.before(DateUtil.offsetSecond(created, time))) {
return true;
}
return false;
}
/**
* 从token中获取用户名
*
* @param token
* @return
*/
public String getUserNameFromToken(String token) {
String username;
try {
Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
} catch (Exception ex) {
return "";
}
return username;
}
/**
* 验证token是否有效
*
* @param token 客户端传入的token
* @param userDetails 从数据库中查询出来的用户信息
* @return
*/
public boolean validateToken(String token, UserDetails userDetails) {
String username = getUserNameFromToken(token);
return username.equals(userDetails.getUsername()) && !isTokenExpire(token);
}
/**
* 判断token是否过期失效
*
* @param token
* @return
*/
private boolean isTokenExpire(String token) {
Date expireDate = getExporeDateFromToken(token);
return expireDate.before(new Date());
}
/**
* 从token中获取过期时间
*
* @param token
* @return
*/
private Date getExporeDateFromToken(String token) {
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
}
/**
* 根据payload生成jwt的token
*/
private String generateToken(Map<String, Object> claims) {
return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS256, secret).compact();
}
/**
* 从token找那个获取荷载payload
*/
private Claims getClaimsFromToken(String token) {
return Jwts.parser()
.setSigningKey(secret).parseClaimsJws(token)
.getBody();
}
/**
* 生成过期时间
*/
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + (expiration==null?604800:expiration) * 1000);
}
//=================RS256===================
/**
* 根据私钥生成token
*
* @param userDetails
* @param privateKey
* @return
*/
public String generateRsaToken(UserDetails userDetails, PrivateKey privateKey) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.RS256, privateKey).compact();
}
/**
* 根据公钥解析token
* @param token
* @param publicKey
* @return
*/
public Claims getClaimsFromRsaToken(String token, PublicKey publicKey) {
return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
}
/**
* 从文件中读取公钥
*
* @param filename 公钥保存路径,相对于classpath
* @return PublicKey 公钥对象
* @throws Exception
*/
public static PublicKey getPublicKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPublicKey(bytes);
}
/**
* 从文件中读取密钥
*
* @param filename 私钥保存路径,相对于classpath
* @return PrivateKey 私钥对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String filename) throws Exception {
byte[] bytes = readFile(filename);
return getPrivateKey(bytes);
}
/**
* 获取公钥
* 公钥的字节形式。
*
* @param bytes 公钥的字节形式
* @return
* @throws Exception
*/
private static PublicKey getPublicKey(byte[] bytes) throws Exception {
bytes = Base64.getDecoder().decode(bytes);
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
/**
* 获取密钥
*
* @param bytes 私钥的字节形式
* @return
* @throws Exception
*/
private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
bytes = Base64.getDecoder().decode(bytes);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
/**
* 读文件
* @param fileName
* @return
* @throws Exception
*/
private static byte[] readFile(String fileName) throws Exception {
return Files.readAllBytes(new File(fileName).toPath());
}
/**
* 写文件
* @param destPath
* @param bytes
* @throws IOException
*/
private static void writeFile(String destPath, byte[] bytes) throws IOException {
File dest = new File(destPath);
if (!dest.exists()) {
dest.createNewFile();
}
Files.write(dest.toPath(), bytes);
}
/**
* 生成 公钥+私钥
*/
public static void main(String[] args) throws Exception {
String secret = "mysecret";//生成密钥的密文
int keySize = 1024;//密钥长度
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
//获取公钥
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);
log.info("publicKeyBytes:{}", new String(publicKeyBytes));
String rsaPubPath = ResourceUtils.getFile("classpath:rsa/id_rsa_pub").getPath();
log.info("rsaPubPath:{}", rsaPubPath);
writeFile(rsaPubPath, publicKeyBytes);
//获取私钥
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);
log.info("privateKeyBytes:{}", new String(privateKeyBytes));
String rsaPrivPath = ResourceUtils.getFile("classpath:rsa/id_rsa").getPath();
log.info("rsaPrivPath:{}", rsaPrivPath);
writeFile(rsaPrivPath, privateKeyBytes);
//根据私钥生成token
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("admin");
authorities.add(authority);
User userDetails = new User("lee","admin123",authorities);
PrivateKey privateKey = getPrivateKey(rsaPrivPath);
JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
String token = jwtTokenUtil.generateRsaToken(userDetails, privateKey);
log.info("token:{}",token);
//根据公钥解析token
PublicKey publicKey = getPublicKey(rsaPubPath);
Claims claims = jwtTokenUtil.getClaimsFromRsaToken(token, publicKey);
log.info("claims:{}", JSON.toJSONString(claims));
}
}
八、项目中使用JWT的鉴权流程
1、
2、