JWT--JSON WEB TOKEN
基于JSON格式的开放式标准的,它是一种简单紧凑安全的,适用于分布式站点的单点登录(sso)场景,JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
传统的session和JWT的区别:
传统的session:
使用session,用户将用户名和密码发送到服务端,服务端保存登录信息,应为http是无状态请求,所以服务器并不能确定是那个用户请求,所以我们只能讲服务端存储的登录信息发送给请求端,将登录信息返回给请求端,保存为cookie,这样下一次请求来的时候,也将cookie放过来,就可以识别用户了。但是当你换到另一台设备请求,没有cookie,这样的话会在服务端保存多个session,会使服务端资源被占用很多。
JWT:
用户使用用户名密码来请求服务器
服务器进行验证用户的信息
服务器通过验证发送给用户一个token
客户端存储token,并在每次请求时附送上这个token值
服务端验证token值,并返回数据
不返回session只返回一个token,这样的话去匹配token
JWT一共由三段信息组成:1.为JWT的头;2.为jwt的信息承载部分;3.签证,亦是通行证
1.头部分:
1)声明类型为JWT
2)声明加密的算法(HMAC,SHA256)
{
'typ': 'JWT',
'alg': 'HS256'
}
之后将头进行base64加密
2.承载信息:playload:1.标准中的注册声明;2.公共的声明;3.私有的声明
标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共声明:可以添加任何信息,但是会在客户端解密
私有声明:是提供者和消费者所共同定义的声明,也可以背解密
playload:{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
之后将playload进行base64加密
3.signature:是一个签证信息:
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后 通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret');
使用JWT步骤 :
1.先导入jar包,导入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
2.编写代码
@Component
public class JwtUtil {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Value("${appconfig.jwt-secret}")
private String JWT_SECRET;
/**
* 生成JWT
* @param claims
* @return
*/
public String generateToken(Map<String, Object> claims ,Date date) {
log.info("JWT_SECRET:"+JWT_SECRET);
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
return Jwts.builder()
.setHeaderParam("typ","JWT")
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(date)
.signWith(SignatureAlgorithm.HS256, JWT_SECRET) //采用什么算法是可以自己选择的,不一定非要采用HS512
.compact();
}
private Date generateExpirationDate(long nowMillis){
long expMillis = nowMillis + 5000000;
Date exp = new Date(expMillis);
return exp;
}
/**
* 解密JWT
* @param token
* @return
*/
public Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(Config.JWT_SECRET)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
log.error("解析JWT Token失败,token无效,Msg:"+e.getMessage());
}
return claims;
}
}