shiro + jwt 快速搭建
前言
一个系统在起步的时候最重要的权限系统,最简单的实现就是通过角色表+菜单表相关联,通过登陆用户的角色查到对应的菜单,但是这样只能得到页面的权限,如何控制某个功能的权限呢?shiro来了...一、jwt是什么?
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。1. jwt构成
JWT是由三段信息构成的,将这三段信息文本用.
链接一起就构成了JWT字符串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
1.1 header
jwt的头部承载两部分信息:
- 声明类型,这里是jwt
- 声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
1.2 playload
载荷就是存放有效信息的地方,这里一般存储用户的非敏感信息,为json格式
{
"username": "joker",
"addr": "北京朝阳区",
"age": 23,
"VIP":false
}
然后将其进行base64加密,得到Jwt的第二部分。
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
1.3 signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header (base64后的)
- payload (base64后的)
- secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
2. jwt实现
引入pom依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>
创建jwt工具类,该类提供了生成token,验证token等方法,同时每次生成等token可以设置有效时间
/*
* 总的来说,工具类中有三个方法
* 获取JwtToken,获取JwtToken中封装的信息,判断JwtToken是否存在
* 1. encode(),参数是=签发人,存在时间,一些其他的信息=。返回值是JwtToken对应的字符串
* 2. decode(),参数是=JwtToken=。返回值是荷载部分的键值对
* 3. isVerify(),参数是=JwtToken=。返回值是这个JwtToken是否存在
* */
@Slf4j
public class JwtUtil {
//创建默认的秘钥和算法,供无参的构造方法使用
private static final String defaultbase64EncodedSecretKey = "badbabe";
private static final SignatureAlgorithm defaultsignatureAlgorithm = SignatureAlgorithm.HS256;
public JwtUtil() {
this(defaultbase64EncodedSecretKey, defaultsignatureAlgorithm);
}
private final String base64EncodedSecretKey;
private final SignatureAlgorithm signatureAlgorithm;
public JwtUtil(String secretKey, SignatureAlgorithm signatureAlgorithm) {
this.base64EncodedSecretKey = Base64.encodeBase64String(secretKey.getBytes());
this.signatureAlgorithm = signatureAlgorithm;
}
/*
*这里就是产生jwt字符串的地方
* jwt字符串包括三个部分
* 1. header
* -当前字符串的类型,一般都是“JWT”
* -哪种算法加密,“HS256”或者其他的加密算法
* 所以一般都是固定的,没有什么变化
* 2. payload
* 一般有四个最常见的标准字段(下面有)
* iat:签发时间,也就是这个jwt什么时候生成的
* jti:JWT的唯一标识
* iss:签发人,一般都是username或者userId
* exp:过期时间
*
* */
public String encode(String iss, long ttlMillis, Map<String, Object> claims) {
//iss签发人,ttlMillis生存时间,claims是指还想要在jwt中存储的一些非隐私信息
if (claims == null) {
claims = new HashMap<>();
}
long nowMillis = System.currentTimeMillis();
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setId(UUID.randomUUID().toString())//2. 这个是JWT的唯一标识,一般设置成唯一的,这个方法可以生成唯一标识
.setIssuedAt(new Date(nowMillis))//1. 这个地方就是以毫秒为单位,换算当前系统时间生成的iat
.setSubject(</