springboot中JJWT的简单使用
一 什么是JWT
jwt全称json web token,是基于json协议的用于结局认证授权的方法。token就是令牌,其主要作用是用来进行授权(Authorization),授权和认证是不同的概念,认证是系统通过账号密码或其他手段来验证身份,授权是在认证后获得系统授予的权限。系统想知道用户有什么权限,需要给用户贴上标签,方式有很多种,token是其中一种。当用户获得token后,用户后续的请求只需附带token,系统便可进行授权。jwt不同与cookie-session,它不会在服务端进行储存,token会被写入进http请求的header或body中进行双向的传输。
JWT组成
JWT由三部分组成,分别是header,playload和signature。由于本文主要写JJWT的使用,JWT结构就不详细展开了,对于这部分还不了解的可以去JWT官网上查看,连接:JWT官网介绍
- Header
- PlayLoad
- Signature
二 什么是JJWT
JJWT旨在成为最易于使用和理解的库,用于在JVM和Android上创建和验证JSON Web令牌(JWT)。 JJWT是完全基于JWT,JWS,JWE,JWK和JWA RFC规范以及Apache 2.0许可条款下的开源的纯Java实现。 该图书馆由Okta的高级建筑师Les Hazlewood创建,并由贡献者社区提供支持和维护。 Okta是面向开发人员的完整身份验证和用户管理API。 我们还添加了一些不属于该规范的便利扩展,例如JWS压缩和声明执行。
以上内容由jjwt官方文档机翻而来
简而言之,JJWT提供了java环境下的使用JWT的能力,使得具体实现对开发者透明,开发者只需用简单几行代码即可创建或者解析一个token。
三 简单入门
- 导入依赖(Maven环境)
<!--老版本-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
注意,现在jjwt已经更新到0.11.0,理论上说0.xx.x到0.xx.x的更新属于兼容性的,但经过尝试,发现还是有不少改动。这里也贴出来最新的版本的Maven工程依赖
<!--新版本-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
- 生成token
jjwt中,使用Jwts.builder()
进行构建token。
// 假设代码块被包含在一个函数中
Map<String, Objcet> claims = new HashMap<>();
// claims就是playload中的内容,可以写入自己需要的键值
claims.put("key", "value");
// 构建
JwtBuilder jwtBuilder = Jwts.builder()
// 设置有效载荷
.setClaims(claims)
// 设置subject
.setSubject(subject)
// 设置签发时间
.setIssuedAt(new Date())
// 采用HS256方式签名,key就是用来签名的秘钥
.signWith(SignatureAlgorithm.HS256, key);
// 调用compact函数将token打包成String并返回
return jwtBuilder.compact();
在上述代码块中,对JWT的playload进行了设置,没有自定义header。
这里采用的HS256加密,HS256是一种对称秘钥加密手段,利用哈希MAC加密方式,即加密解密都使用相同的秘钥"key"。也可以采用RS256加密或者其他加密方法,RS256是公开秘钥加密,秘钥分为公钥和私钥,私钥用于生成JWT,公钥用于解密,想知道更具体的可以学习信息安全。但无论哪种加密方法,都得保护好秘钥,并确保秘钥难以被碰撞。
- 服务端发送token
在步骤2中调用compact()
会生成一长串经过编码的字符串,字符串格式为xxxxxx.xxxxxxxx.xxxxxxx,三个部分分别对应头,载荷和签名。将token发送给客户端往往通过httpheaders中的Authorization字段发送。当然也可以放在http数据包中发送给客户端。
// 在header中写入Authorization
@RequestMapping(value = "/jwttest1", method = RequestMethod.GET)
public String test1(HttpServletRequest request, HttpServletResponse response) {
// 通过步骤2中的方法获取token
String token = ...
response.setHeader("Authorization", token);
return "success";
}
这里要注意,在前端如果是跨域请求,js获取heaer中隐私的信息在规范中是不安全的,所以服务器需设置,让这个header暴露出来
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.exposedHeaders("Authorization");
}
- 服务端解析token
发送token后,客户端的请求会附带token,token同样可以放httpheader中或报文中,接下来需要解析token
@RequestMapping(value = "/jwttest2", method = RequestMethod.GET)
public void test2(HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader("Authorization");
// 调用下面写的方法解析即可,由于没有写方法的类,这里就不演示了
}
// 解析token
public Claims jwtParser(String token) {
Claims claims;
// token不一定通过验证,所以需要包裹try-catch捕获jjwt提供的JwtException
try {
claims = Jwts.parser()
// HS256是对称加密体系,加密解密使用同一个key
.setSigningKey(key)
.parseClaimsJws(token)
.getBody();
} catch (JwtException e) {
claims = null;
e.printStackTrace();
}
return claims;
}
获取到的claims就是playload,如果是playload中的标准字段可以直接通过函数取出如
String subject = (String) claims.getSubject();
如果是自己自定义的键值可以通过get()
方法取出,假设储存的值可以转换String
String value = (String) claims.get("key");
这样就获取到并解析了token。