1.介绍
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
实现是 一个 加密的字符串 ,这个字符串存储了用户的身份凭证 等信息
什么是jwt?
JSON Web Token (JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对进行签名,防止被篡改。
JWT官网: https://jwt.io
JWT令牌的优点:
- JWT基于json,非常方便解析。
- 可以在令牌中自定义丰富的内容,易扩展。
- 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。
- 资源服务使用JWT可不依赖认证服务即完成授权。
JWT令牌的缺点:
- JWT令牌较长,占存储空间比较大。
jwt 组成
一个JWT实际上就一个字符串,它由三部分组成,头部、负载与签名。
2.快速开始
2.1添加依赖
<!-- JWT -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
2.2创建工具类
package com.qf.eduonline.utils;
import com.qf.eduonline.common.CheckResult;
import com.qf.eduonline.constant.SystemConstant;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SignatureException;
import java.util.Date;
/**
* 前端发送认证请求 比如用户名密码 认证通过后 后台生成一个 token
* 发送给前端 前端存储到 localstorage 以后每次请求 都带这个token 发送到后台 去验证
*
*
*
* @date 2021/5/9 20:44
*/
public class JwtUtils {
/**
* 签发JWT
* @param id
* @param subject 可以是JSON数据 尽可能少
* @param ttlMillis
* @return
*/
public static String createJWT(String id, String subject, long ttlMillis) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
SecretKey secretKey = generalKey();
JwtBuilder builder = Jwts.builder()
.setId(id)
.setSubject(subject) // 主体 一般是用户名
.setIssuer("glls") // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis; // 当前时间 + 有效时间
Date expDate = new Date(expMillis); // 过期时间
builder.setExpiration(expDate); // 设置过期时间
}
return builder.compact();
}
/**
* 验证JWT
* @param jwtStr
* @return
*/
public static CheckResult validateJWT(String jwtStr) {
CheckResult checkResult = new CheckResult();
Claims claims = null;
try {
claims = parseJWT(jwtStr);
checkResult.setSuccess(true);
checkResult.setClaims(claims);
} catch (ExpiredJwtException e) {
checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
checkResult.setSuccess(false);
} catch (SignatureException e) {
checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
checkResult.setSuccess(false);
} catch (Exception e) {
checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
checkResult.setSuccess(false);
}
return checkResult;
}
/**
* 生成加密Key
* @return
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 解析JWT字符串
* @param jwt
* @return
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
public static void main(String[] args) throws InterruptedException {
// 后端生成token
String sc=createJWT("1","jack",SystemConstant.JWT_TTL);
System.out.println(sc);
// 后端验证token
CheckResult checkResult = validateJWT(sc);
System.out.println(checkResult.isSuccess());
System.out.println(checkResult.getErrCode());
Claims claims=checkResult.getClaims();
System.out.println(claims);
System.out.println(claims.getId());
System.out.println(claims.getSubject());
// 刷新token 重新生成token
Claims claims2=validateJWT(sc).getClaims();
String sc2=createJWT(claims2.getId(),claims2.getSubject(),SystemConstant.JWT_TTL);
System.out.println(sc2);
}
}
配套 常量类 和 结果类
package com.qf.eduonline.constant;
/**
* @ClassName : SystemConstant
* @Author : glls
* @Date: 2021/5/9 20:30
* @Description :
*/
public class SystemConstant {
/**
* token
*/
public static final int JWT_ERRCODE_NULL = 4000; //Token不存在
public static final int JWT_ERRCODE_EXPIRE = 4001; //Token过期
public static final int JWT_ERRCODE_FAIL = 4002; //验证不通过
/**
* JWT
*/
public static final String JWT_SECERT = "8677df7fc3a34e26a61c034d5ec8245d"; //密匙
public static final long JWT_TTL = 60 * 60 * 1000; //token有效时间
}
package com.qf.eduonline.common;
import io.jsonwebtoken.Claims;
public class CheckResult {
private int errCode;
private boolean success;
private Claims claims;
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public Claims getClaims() {
return claims;
}
public void setClaims(Claims claims) {
this.claims = claims;
}
}
3.认证成功 发送token
@PostMapping("/login")
public JsonResult login(@RequestBody User user){
User currentUser = userService.login(user);
if(currentUser==null){
//认证失败
return JsonResult.ok(currentUser);
}else {
//认证成功 向前端 发送token
String token = JwtUtils.createJWT(String.valueOf(currentUser.getUserId()),currentUser.getRealname(), SystemConstant.JWT_TTL);
return JsonResult.ok(token);
}
}
4.前端接受token 并存起来 以后每次请求在请求头上携带token
//整合 jwt 返回的是 token 后面的请求 就需要携带token
var token = resp.data.data;
//把响应结果的token 存到 localStorage
window.localStorage.setItem("token",token);
后续请求携带token
let token = window.localStorage.getItem("token");
this.axios.defaults.headers.common["token"] = token; // 请求头上带token
标签:return,JWT,checkResult,token,claims,public
From: https://blog.51cto.com/u_16254019/7412473