Token详解

一、token是什么?

Token是用户进行一些权限操作时的许可凭证。token本质是字符串,里面包含了用户信息,过期时间,加密方式等。token是在前端进行登录之后,由服务器分发给前端,然后前端进行权限操作时,再将token发送给服务器,由服务器来验证。token是有过期时间的,一但token过期,用户就要重新登陆让服务器生成新的token。

token的验证流程如下

  • 客户端使用用户名和密码请求登录
  • 服务端收到请求,验证用户名和密码
  • 验证成功后,服务端会签发一个token,再把这个token返回给客户端
  • 客户端收到token后可以把它存储起来,比如放到cookie中
  • 客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带
  • 服务端收到请求,然后去验证客户端请求里面带着的token,如果验证成功,就向客户端返回请求数据

二、jwt

JWT全名json web token, JWT就是上述流程当中token的一种具体实现方式,它由三个部分组成,并每个部分由.来连接。

  • 头部(head)
  • 负载(payload)
  • 签名(Signature)

因此jwt会是这个样子xxxxx.yyyyy.zzzzz

2.1 Header 标头

标头通常由两部分组成:令牌的类型,即JWT,以及正在使用的签名算法,如HMAC SHA256或RSA。如下所示

{
  "alg": "HS256",
  "typ": "JWT"
}

之后这段代表会用base64url进行编码来形成jwt的第一部分。

2.2 Payload 负载

jwt的第二部分是负载,负载里面包含了许多声明(例如用户信息)。一共有三种类型的声明(registered,public,private)

  • registered 该声明是预定义的,不是强制性的,但是是推荐的。其中一些是:iss(发行者)、exp(过期时间)、sub(主题)、aud (用户)、iat(发布时间)、jti(JWT ID用于标识该JWT)等。(注意:jwt中json声明的名字都是三个字母)

  • public 这部分是用户自己定义的。注意不要跟registerd的冲突。

  • private 这些是为在同意使用它们的各方之间共享信息而创建的定制声明,它们既不是registered的,也不是public声明。

    注意:不要将未加密的秘密信息放在头部或者负载。因为他们是可读的。
    

之后负载会用Base64rul进行编码作为jwt的第二部分。

2.3 Signature 签名

签名是拿到被base64编码的标头和负载后,用标头里的加密算法对拿到的标头和负载进行加密,然后作为jwt的第三部分。签名是用来验证标头和负载中的信息有没有被篡改。如果标头和负载的信息被篡改,则这个jwt是失效的。反之验证通过。
流程如下。

首先,需要指定一个密钥(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用header中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名
HMACSA256( base64UrlEncode(header) + " . " +base64UrlEncode(payload) , secret )
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用.分隔,就构成整个JWT对象。

三、Java中使用jwt

java中最常用的库是java-jwt。pom坐标如下。

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>4.0.0</version>
</dependency>

3.1 使用步骤

3.1.1 生成jwt

  1. 指定算法。
//HMAC
Algorithm algorithmHS = Algorithm.HMAC256("secret"); //use more secure key

//RSA
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);
//Rsa是一种非对称算法 验证时候需要公钥和私钥,私钥一般是存放在服务器里。
  1. 创建 jwt 并添加指定 payload
Map <String, Object> map =  Map<String,String> map = new HashMap<>(); //自定义payload
map.put("age",11);
JWT.create().withPayload(map).withKeyId(String.valueOf(123)).withIssuer("Tom").withExpiresAt(calendar.getTime()).sign(algorithmRS);

最后一定要调用sign传入第一步的算法对象,签署电子签名。

上述代码生成的jwt转成json后如下。

head
{
  "kid": "123",
  "typ": "JWT",
  "alg": "RS256"
}
payload
{
  "iss": "Tom",
  "exp": 1663816787
  "age":11
}

3.1.2 验证jwt

 try {
 	    //要验证的jwt
 		String token = "eyJraWQiOiI4IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiLnrb7lj5HogIUiLCJleHAiOjE2NjM4MTY3ODd9.U3PyZobW2KwZ4a_kQ3soZzEQtAj0sh8vKDR5ZC916BE-tRUM8RaoeWfw6Y40REjbUCGIp6fqRPsxUf7LDGmo1okfkfzkXBnfKTF93UNiqmFLfNWp5tXwCeUmoN0a3S_9Fu6v8nOp8M38eTIoz2Z719LGU92Fbht-PtHpqB_WZ1Q""
 		//指定解析的算法
        Algorithm algorithm = Algorithm.RSA256(RSAUtil.getPublicKey(),RSAUtil.getPrivateKey()); 
        //生成解析器
        JWTVerifier verifier = JWT.require(algorithm).build();
        //如果验证失败会抛出异常
        DecodedJWT jwt = verifier.verify(token);  
        //获取jwt的keyid
        String userID = jwt.getKeyId();  
      }
    catch (TokenExpiredException e ){
           ...
      }

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值