【jwt】JWT原理,JWT是用来解决什么问题的,如何自定义生成JWT数据,并且实现jwt数据的解码

JWT: JSON Web Token

1. jwt概述

用户登录成功后,服务端 如何知道客户端的每次请求对应的是哪个用户呢?怎么做:目前有两种方式实现.

1.1. 一是通过sessionId的方式,登录成功后服务端返回sessionId给客户端,然后浏览器将sessionId保存在Cookie中,这样每次浏览器请求的时候都带上sessionId,通过sessionId就能在服务端找到对应的session,就能知道是哪个用户。 (session里记录了用户的相关信息,登录时间等)

1.2. 二是用户登录成功后,服务端根本就不存用户的session信息,用户登录成功后,服务端将用户的信息返回给客户端,客户端自己保存用户信息,然后每次客户端请求的时候,将用户信息传给服务端,这就是jwt的原理。

2. JWT 的原理

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。


{
  "name": "jack",
  "role": "admin",
  "id": 123456
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

3. jwt数据结构

jwt是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

JWT 的三个部分依次如下。

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

类似这样的:

 

3.1 Header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。


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

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串。

3.2 Payload

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。


{
  "sub": "1234567890",
  "username": "John Doe",
  "userId": 123654
}

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

这个 JSON 对象也要使用 Base64URL 算法转成字符串。

3.3 Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。


HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

3.4 Base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

4、 使用 jwt 

客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面。

类似这样,这些数据传输:

Authorization: Bearer <token>

5、 自定义实现jwt 

说了这么多,结下来我们自己来实现定义一个jwt数据的生成,jwt数据的解码工作,通过目前市面上开源的java-jwt jar包,还是很方便的


import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.gfm.asset.base.exception.InteractException;
import lombok.SneakyThrows;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author xxx 
 */
public class JwtHelper {
    private static final Logger logger = LoggerFactory.getLogger(JwtHelper.class);


    /**
     * 密钥加密token
     */
    @SneakyThrows
    public static String generateToken(String userKey, String secretKey, int expire) {
        Algorithm algorithm = Algorithm.HMAC256(secretKey);
        String token = JWT.create()
                .withIssuer(userKey)
                .withIssuedAt(new Date())
                .withExpiresAt(DateTime.now().plusSeconds(expire).toDate())
                .sign(algorithm);
        logger.info("==> 生成jwtToken, userKey={},secretKey={},过期时间={}s,token={}", userKey, secretKey, expire, token);
        return token;
    }

    /**
     * 公钥解析token
     */
    public static String parserToken(String token, String secretKey) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secretKey);
            DecodedJWT jwt = JWT.require(algorithm)
                    .build().verify(token);
            return jwt.getIssuer();
        } catch (TokenExpiredException e) {
            throw new InteractException("token has expired");
        } catch (Exception e) {
            e.printStackTrace();
            throw new InteractException("token is invalid");
        }
    }

    public static void main(String[] args) { 
        String userKey = "center_sys";
        String secretKey = "center_sys@#$";
        String token = generateToken(userKey, secretKey, 60 * 60 * 24 * 7);
        System.out.println(token);
//        String key = parserToken(token, secretKey);
//        System.out.println(key);
    }


}

pom.xml文件

  <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.19.1</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

参考:

JSON Web Token 入门教程 - 阮一峰的网络日志

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值