JWT & 用户身份认证演变过程
<session-config> <session-timeout>30</session-timeout> </session-config>
session.invalidate();
// 保存 redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS); // 设置过期时间 > 0 redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); // 删除 redisTemplate.delete(key); // 是否存在key redisTemplate.hasKey(key); // 根据key获取 redisTemplate.opsForValue().get(key);
{header_urlbase64}.{payload_urlbase64}.{signature}
- header
{
"alg": "HS256",
"typ": "JWT"
}
- payload
iss (issuer):签发人 exp (expiration time):过期时间 sub (subject):主题 aud (audience):受众 nbf (Not Before):生效时间 iat (Issued At):签发时间 jti (JWT ID):唯一id
{
"exp": 1664365790511,
"tenantId": "1",
"appId": "",
"userId": "131SG161E610001",
"serverToken": "7360dbb8-067d-4339-90a4-8955921c9e65",
"refreshToken": "d2b0083f-442d-42ea-a765-3c98d95119cb",
"expiredTime": 0,
"reloginVersion": 0,
"ip": "127.0.0.1"
}
- signature
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

Tips
什么是base64UrlEncode? Base64有三个字符+、/和=,在URL里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。
- 服务端不能主动让token失效
<!-- JWT maven 依赖 --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
package com.admin.api.utils; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import com.admin.api.constant.Constants; import com.alibaba.fastjson.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import io.jsonwebtoken.Claims; import io.jsonwebtoken.CompressionCodecs; import io.jsonwebtoken.Jws; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; /** * Jwt工具类 * @author wang_dgang * @since 2018-10-23 10:28:40 */ public class JwtUtil { // 日志 private static final Logger log = LoggerFactory.getLogger(JwtUtil.class); // JWT 加解密类型 private static final SignatureAlgorithm JWT_ALG = SignatureAlgorithm.HS512; /** * 生成JWT * @param subjectJson JSON * @param expire 超时时间,单位秒 * @return */ public static String buildJWT(String subjectJson, int expire) { // 生成JWT的时间 Date startDate = DateUtil.date(); // 过期时间 Date endDate = DateUtil.offset(startDate, DateField.SECOND, expire); // 为payload添加各种标准声明和私有声明 JwtBuilder builder = Jwts.builder() // new一个JwtBuilder,设置jwt的body .setId(IdUtil.simpleUUID()) // JWT的唯一标识,回避重放攻击 .setExpiration(endDate) // 过期时间 .setIssuedAt(startDate) // 签发时间 .setSubject(subjectJson) // json格式的字符串 // .compressWith(CompressionCodecs.DEFLATE) // 压缩 .signWith(JWT_ALG, generalKey()); // 设置签名算法和密钥 return builder.compact(); } /** * 生成JWT * @param claims Map * @param expire 超时时间,单位秒 * @return */ public static String buildJWT(Map<String, Object> claims, int expire) { // 生成JWT的时间 Date startDate = DateUtil.date(); // 过期时间 Date endDate = DateUtil.offset(startDate, DateField.SECOND, expire); // 为payload添加各种标准声明和私有声明 JwtBuilder builder = Jwts.builder() // new一个JwtBuilder,设置jwt的body .setClaims(claims) // 设置payload数据,需先进行设置,会覆盖其他属性 // .setId(IdUtil.simpleUUID()) // JWT的唯一标识,回避重放攻击 .setExpiration(endDate) // 过期时间,需设置在claims之后,否则会被覆盖 // .compressWith(CompressionCodecs.DEFLATE) // 压缩 .signWith(JWT_ALG, generalKey()); // 设置签名算法和密钥 return builder.compact(); } /** * Jwt验证(true:验证通过,false:验证失败) * @param jwt 内容文本 * @return */ public static boolean checkJWT(String jwt) { return ObjectUtil.isNotNull(getClaimsJws(jwt)); } /** * parseClaimsJws * @param jwt 内容文本 * @return */ private static Jws<Claims> getClaimsJws(String jwt) { Jws<Claims> parseClaimsJws = null; try { SecretKey generalKey = generalKey(); JwtParser parser = Jwts.parser().setSigningKey(generalKey); parseClaimsJws = parser.parseClaimsJws(jwt); } catch (Exception e) { log.warn("JWT验证失败,原因:{}", e.getMessage()); } return parseClaimsJws; } /** * 生成加密key * @return */ private static SecretKey generalKey() { return JwtSecretKeyHolder.instance; } private static class JwtSecretKeyHolder { // 服务端保存的jwt秘钥转为字节数组 static final byte[] encodedKey = Constants.JWT_SECRET.getBytes(); private static final SecretKey instance = new SecretKeySpec(encodedKey, JWT_ALG.getJcaName()); } /** * Jwt解析 * @param jwt 内容文本 * @return Subject中json串 */ public static String parseJWT(String jwt) { Jws<Claims> claimsJws = getClaimsJws(jwt); Claims body = claimsJws.getBody(); // 获取加密的内容JSON并返回 String subjectJson = body.getSubject(); return subjectJson; } /** * Jwt解析 * @param jwt * @return Claims对象,直接get获取对应值 */ public static Claims parseJWTMap(String jwt) { Jws<Claims> claimsJws = getClaimsJws(jwt); Claims body = claimsJws.getBody(); return body; } // demo public static void main(String[] args) throws InterruptedException, RuntimeException { // 包装payload数据 JSONObject json = new JSONObject(); json.put("name", "77hub"); json.put("userId", "131SG161E610001"); json.put("serverToken", "7360dbb8-067d-4339-90a4-8955921c9e65"); // 生成jwt String jwtWithExpire = buildJWT(json.toJSONString(), 2); System.out.println(jwtWithExpire); // Thread.sleep(3 * 1000); // 解析,获取Subject中的json串 System.out.println(parseJWT(jwtWithExpire)); System.out.println(); System.out.println("---------------------------------"); System.out.println(); // 包装payload数据 Map<String, Object> claimsMap = new HashMap<>(); claimsMap.put("name", "77hub"); claimsMap.put("userId", "131SG161E610001"); claimsMap.put("serverToken", "7360dbb8-067d-4339-90a4-8955921c9e65"); // 生成jwt String buildJWT = buildJWT(claimsMap, 2); System.out.println(buildJWT); // Thread.sleep(3 * 1000); // 解析jwt Claims claims = parseJWTMap(buildJWT); System.out.println(claims.get("name")); System.out.println(claims.get("serverToken")); } }
(1)access_token
(2)refresh_token
sha256(client_id + refresh_token + client_secret)

假设有一个用户需要在后台管理界面上操作6个小时。




优点:
缺点:
{
"exp": 1664365790511,
"tenantId": "1",
"appId": "",
"userId": "131SG161E610001",
"serverToken": "7360dbb8-067d-4339-90a4-8955921c9e65",
"refreshToken": "d2b0083f-442d-42ea-a765-3c98d95119cb",
"expiredTime": 0,
"reloginVersion": 0,
"ip": "127.0.0.1"
}
接着看这个博客补充
https://sunshinehu.blog.csdn.net/article/details/127526921?spm=1001.2014.3001.5502





浙公网安备 33010602011771号