jwt
jwt是Json Web Token缩写。它将用户信息加密到token里,服务器不用保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即可验证通过。
- 优点:在分布式系统中,很好地解决了单点登录问题,很容易解决了session共享的问题。
- 缺点
(1) 无法作废已颁发的令牌
(2) 不易应对数据过期的问题
概念介绍
JWT消息构成
一个token分3部分,按顺序为:
- header:头信息
- payload:载荷-消息体
- signature:签名信息
这里由3部分组成,之间用“.”号做分隔。例如: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
头信息
头部由2部分组织
- 声明类型,这是是jwt
- 声明加密的算法,通常直接使用HMAC SHA256
JWT里验证和签名使用的算法,可选择下面的
JWS 算法名称 描述
HS256 HMAC256 HMAC with SHA-256
HS384 HMAC384 HMAC with SHA-384
HS512 HMAC512 HMAC with SHA-512
RS256 RSA256 RSASSA-PKCS1-v1_5 with SHA-256
RS384 RSA384 RSASSA-PKCS1-v1_5 with SHA-384
RS512 RSA512 RSASSA-PKCS1-v1_5 with SHA-512
ES256 ECDSA256 ECDSA with curve P-256 and SHA-256
ES384 ECDSA384 ECDSA with curve P-384 and SHA-384
ES512 ECDSA512 ECDSA with curve P-521 and SHA-512
代码指定头信息
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
载荷(playload)-消息体
载荷就是存放有效信息的地方。基本上有2种数据类型。
- 标准中注册的声明的数据
- 自定义数据
在这2部分内部做base64加密。最终将数据保存到JWT的chaims里
- 标准中的声明(建议但不强制使用)
iss:jwt签发者
sub:jwt所面向的用户
aud:接受jwt的一方
exp:jwt的过期时间,这个过期时间必须要大于签发时间
nbf:定义在什么时间之前,该jwt都是不可用的
iat:jwt的签发时间
jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
使用方法
JWT.create().withHeader(map) //header
.withClaim("iss", "Service") //payload
.withClaim("aud", "APP")
.withIssuedAt(iatDate) //sign time
.withExpireAt(expiresDate) //expire time
- 自定义数据
这个比较简单,存放我们想放在token中存放的key-value值
使用方法
JWT.create().withHeader(map) //header
.withClaim("name", "cy") //payload
.withClaim("user_id", "112233");
签名信息(signature)
jwt的第3部分是一个签证信息,这个签证信息算法如下:
base64UrlEncode(header) + "." + base64UrlEncode(payload) + 你的256-bit-secret
这部分需要对header和payload进行base64编码,然后通过“.”连接成字符串,然后通过header中申明的加密方式进行加盐secret组合加密,然后就构成了jwt的第3部分。
到目前为止,JWT的api相关知识已经学完了,但是API不够友好,不停地用withClaim放数据。不太好用,下面推荐一个款框架,相当于对JWT的实现框架
JWT
它是为了更友好的在JVM上使用JWT,是基于JWT,JWS,JWK框架的java实现。
参考地址:https://github.com/jwtk/jjwt
基本使用
Maven引入JJWT
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<!-- Uncomment this next dependency if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
<scope>runtime</scope>
</dependency>
-->
生成token
import com.sun.javafx.scene.traversal.Algorithm;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.DefaultJwsHeader;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
private String SECRET = "DyoonSecret_0581";
private void getJwtToken(){
Date iatDate = new Date();
// expire time
Calendar nowTime = Calendar.getInstance();
//有10天有效期
nowTime.add(Calendar.DATE, 10);
Date expiresDate = nowTime.getTime();
Claims claims = Jwts.claims();
claims.put("name","cy");
claims.put("userId", "222");
claims.setAudience("cy");
claims.setIssuer("cy");
String token = Jwts.builder().setClaims(claims).setExpiration(expiresDate)
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
上面将token中的载荷放在chaims中,其实chaims是JWT内部维持的一个存放有效信息的地方,不论使用任何API,最终都使用chaims保存信息。 setClaims有2个重载
JwtBuilder setClaims(Claims claims);
JwtBuilder setClaims(Map<String, Object> claims);
解析token
public void parseJwtToken(String token) {
try{
}catch (Exception e){
}
Jws<Claims> jws = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);
String signature = jws.getSignature();
Map<String, String> header = jws.getHeader();
Claims Claims = jws.getBody();
}
本文暂时没有评论,来添加一个吧(●'◡'●)