JWT--token 认证
目录
常见的认证方式
- http basic auth: 最简单的每次都要认证用户名和密码,不安全、麻烦、所以不采用
- cookie+session: 比较常用,但是比较费服务器空间,服务器需要为每个用户开辟session空间
- OAuth第三方授权:
用户在访问虾米app时需要使用qq账号登陆,于是qq认证服务器让用户授权,用户授权通过后,qq服务器发一个令牌给虾米,虾米带着这个令牌去qq资源服务器获取用户的基本信息(昵称、头像、性别等),虾米再把信息展示给用户。
- 基于Token的认证
客户端在服务器端登陆成功以后,服务器会创建一个token,保存在redis中,并且把这个token发送给客户端。客户端下次访问资源时会自动携带这个token,服务器拿到token去redis中验证,如果验证通过就把信息进行返回。
token认证的优点:比http basic auth安全、比cookie节省服务器空间,比oauth认证要轻巧,应用场景也不同。
token的优点:
- 可以不需要通过cookie来保存,让前端把token放到请求头里传递给后端,不受cookie的跨域限制。
- token和uuid还是有区别的,因为可以直接通过token的解码来获取用户的部分信息。-- jwt 通过base64编码将用户信息编码成token,因此可以通过base64解码获取token中的用户信息
一、JWT
1.jwt介绍
Json web token 是一种存储和传输数据的标准。jwt由三个部分组成: 头部、负载、签名
1)头部
头部用来存放描述jwt的基本信息,比如类型、算法
{
"alg": "HS256",
"typ": "JWT"
}
使用base64编码后:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9,也就是说使用base64解码后能还原字符串信息
2)负载
分成了两种声明:
- 公共的声明:存放一些标准的信息,固定的键
- 私有的声明:存放自定义信息
{
"sub": "use001",
"name": "weixiang",
"iat": 1516239022
}
3)签名
通过用户指定的盐,来生成签名,用于服务端的安全验证。但不能保证jwt中负载中数据的必然的安全。
二、JWT的官方推荐类库-JJWT
1.引入依赖
<!--jjwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
2.创建token
@Test
public void createToken(){
//创建JWT对象
JwtBuilder jwtBuilder = Jwts.builder()
.setId("1001")//设置公共参数id
.setSubject("xiaowang")//设置对象名
.setIssuedAt(new Date())//设置签发时间
.signWith(SignatureAlgorithm.HS256, "qfjava");//设置签名
//得到token
String token = jwtBuilder.compact();
System.out.println(token);
}
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoieGlhb3dhbmciLCJpYXQiOjE2MTU5NDk2NjJ9.MSGqmONhNdxDG0XldhZQ1iXpY4IfU-PjmjS3MpHMb64
3.解析token,获取token中的数据
/**
* 解析token
*/
@Test
public void parseToken(){
String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoieGlhb3dhbmciLCJpYXQiOjE2MTU5NDk2NjJ9.MSGqmONhNdxDG0XldhZQ1iXpY4IfU-PjmjS3MpHMb64";
Claims claims = Jwts.parser().setSigningKey("qfjava").parseClaimsJws(token).getBody();//设置签名
System.out.println("id:"+claims.getId());//获取token中的数据
System.out.println("subject:"+claims.getSubject());
System.out.println("time:"+claims.getIssuedAt());
}
4.设置token的超时时间
/**
* 设置token的过期时间
*/
@Test
public void testExp(){
long now = System.currentTimeMillis();
long exp = now + 60*1000;//设置过期的时间的毫秒值
Date expDate = new Date(exp);
//创建JWT对象
JwtBuilder jwtBuilder = Jwts.builder().setId("1001")//设置公共参数id
.setSubject("xiaowang")//设置对象名
.setIssuedAt(new Date())//设置签发时间
.setExpiration(expDate)//过期的时间点
.signWith(SignatureAlgorithm.HS256, "qfjava");//设置签名
//得到token
String token = jwtBuilder.compact();
System.out.println(token);
}
5.创建带自定义声明的token
/**
* 创建token
*/
@Test
public void createCustomToken(){
//创建JWT对象
JwtBuilder jwtBuilder = Jwts.builder().setId("1001")//设置公共参数id
.setSubject("xiaowang")//设置对象名
.setIssuedAt(new Date())//设置签发时间
.claim("role","student")
.claim("class","java2007")
.signWith(SignatureAlgorithm.HS256, "qfjava");//设置签名
//得到token
String token = jwtBuilder.compact();
System.out.println(token);
}
6.解析自定义声明的token
/**
* 解析自定义声明的token
*/
@Test
public void parseClaimToken(){
String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoieGlhb3dhbmciLCJpYXQiOjE2MTU5NTA0OTksInJvbGUiOiJzdHVkZW50IiwiY2xhc3MiOiJqYXZhMjAwNyJ9.dSiMUMpqvCJIZFVRRPO5tRho3ue2qCuEYQP0r2JrJvQ";
Claims claims = Jwts.parser().setSigningKey("qfjava").parseClaimsJws(token).getBody();//设置签名
System.out.println("role:"+claims.get("role"));
System.out.println("class:"+claims.get("class"));
}