1.JWT
Json web token (JWT),主要用于做身份鉴别或者资源接口的安全机制。
2.基于session认证显露的问题
1.session通常都是保存在内存中的,随着认证用户的增多,服务器的资源消耗会增大。
2.用户认证的信息保存在内存中,这就意味着用户下次请求还必须请求这台服务器,才能拿到授权的资源,
这样在分布式系统限制了应用的扩展能力。
3.cookie如果被截获,用户容易受到跨站请求伪造攻击。
3.JWT的构成
第一部分:头部(header)
第二部分:负载(payload)
第三部分:签证(signature)
header
JWT的头部承载两部分信息:
{
'typ':'JWT', //声明类型
'alg':'HS256' //声明加密的算法
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。
playload
载荷就是存放有效信息的地方。
1.标准中注册的声明。
2.公共的声明
3.私有的声明
标准中注册的声明(建议但不强制使用):
1.iss:JWT签发者
2.sub:JWT所面向的用户
3.aud:接收JWT的一方
4.exp:JWT的过期时间,这个过期时间必须要大于签发时间
5.nbf:定义在什么时间之前,该JWT都是不可用的
6.iat:JWT的签发时间
7.jti:JWT的唯一身份标识
公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务信息,但不建议添加敏感信息,因为
该部分在客户端可以解密。
私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着
该部分信息可以归类为明文信息。
定义一个payload:
{
"sub":"xxxxx",
"name":"John Doe",
"admin":"xx"
}
然后进行base64加密,得到JWT的第二部分。
signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:
1.header(base64加密后)
2.payload(base64加密后)
3.secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header
中声明的加密方式进行加盐secret组合加密,然后就构成了JWT的第三部分。
a1 = base64UrlEncode(header)+"."+base64UrlEncode(payload);
signature = HMACSHA256(a1,'secret');
base64UrlEncode(header).base64UrlEncode(payload).signature
4.JWT实战
1.导入pom
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.1</version>
</dependency>
2.JwtService
package com.ldd.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
/**
* @author 小李同学
* @pageage com.ldd.utils
* @date
* @week
* @action
*/
@Slf4j
public class JwtService {
//定义加密的盐信息
private static final String KEY = "siZong";
//签发者
private static final String ISSUSER = "YYKK";
//token过期时间
private static final Long TOKEN_EXPIRE_TIME = 1000 * 60L;
/**
* @Author: 13513
* @Date: 2021/9/5 13:05
* @Param:
* @Return: 创建jwt 可以指定如下参数
* JWT.create().withIssuer("签发人")
* .withExpiresAt(new Date())...//到期时间 超过到期时间会抛出TokenExpiredException
* iss (issuer):签发人
* exp (expiration time):过期时间
* sub (subject):主题
* aud (audience):受众
* nbf (Not Before):生效时间
* iat (Issued At):签发时间
* jti (JWT ID):编号
* 注意:不设置过期时间就是永久token
*/
public String createToken() {
Date now = new Date();
//1.定义算法
Algorithm algorithm = Algorithm.HMAC256(KEY);
//2.开始创建和生成token
String token = JWT.create()
.withIssuer(ISSUSER) //签发者
.withIssuedAt(now) //签发时间
.withExpiresAt(new Date(now.getTime() + TOKEN_EXPIRE_TIME))
.withClaim("userName", "userName")
.withClaim("openId", "openId")
.sign(algorithm);
return token;
}
public String verifyToken(String token) {
//1.定义算法
Algorithm algorithm = Algorithm.HMAC256(KEY);
//2.进行校验
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(ISSUSER)
.withClaim("userName", "userName")
.build();
//3.如果校验成功,可以从jwt获取定义的内容
// 如果校验失败,则抛出异常
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaim("openId").asString();
}
public static void main(String[] args) {
JwtService jwtService = new JwtService();
String token = jwtService.createToken();
log.info("token:" + token);
String openId = jwtService.verifyToken(token);
log.info("openId:" + openId);
}
}