JWT教程

JWT教程

官方地址:https://jwt.io

在这里插入图片描述

What is JSON Web Token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA. —[摘自官网]

什么是JSON Web Token?

jsonwebtoken(JWT)是一个开放标准(rfc7519),它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全地传输信息。此信息可以验证和信任,因为它是数字签名的。jwt可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名

什么时候使用JWT

  • 授权

    这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够在不同的域中轻松使用。

  • 信息交换

    JSON Web Token是在各方之间安全地传输信息的好方法。因为可以对JWT进行签名(例如,使用公钥/私钥对),所以您可以确保发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否遭到篡改。

JWT的结构是什么样的?

在其紧凑的形式中,JWT由三部分组成,由点(.)分隔,分别是:

  • 标头(Header)
  • 有效载荷(PayLoad)
  • 签名(Signature)

因此,JWT通常用下面的形式展示: xxxxx.yyyyy.zzzzz

  1. 标头(Header)

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

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

这个 JSON 被Base64Url编码以形成 JWT 的第一部分。该信息仅仅使用了base编码,所以任何人都可以解码获取到原信息。

  1. 有效载荷(PayLoad)

令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的陈述。声明分为三种类型:注册声明、公开声明和私人声明。

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

有效载荷是Base64Url编码形成JSON Web令牌的第二部分。该信息仅仅使用了base编码,所以任何人都可以解码获取到原信息,所以不要将敏感信息放到里面。

  1. 签名(Signature)

要创建签名部分,您必须获取编码的标头(Header)、编码的有效载荷(PayLoad)以及一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。签名的作用是保证 JWT 没有被篡改过。

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

后一步签名的过程,实际上是对头部以及负载内容进行签名,防止内容被窜改。如果有人对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的。

JWT签名生成?

jwt在线生成网址为:https://jwt.io/

在这里插入图片描述

JWT优势是什么?

  • 简洁

    由于 JSON 不像 XML 那样冗长,因此在对其进行编码时,它的大小也更小,这使得 JWT 比 SAML 更紧凑。这使得 JWT 成为在 HTML 和 HTTP 环境中传递的不错选择。

  • 安全

    SWT 只能通过使用 HMAC 算法的共享密钥进行对称签名。但是,JWT 和 SAML 令牌可以使用 X.509 证书形式的公钥/私钥对进行签名。与签署 JSON 的简单性相比,使用 XML 数字签名签署 XML 而不引入隐蔽的安全漏洞是非常困难的。

  • 跨语言

    因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。

  • 适用于分布式微服

    不需要在服务端保存会话信息,特别适用于分布式微服务。

快速上手

  1. 引入依赖

    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.19.2</version>
    </dependency>
    
  2. 使用HS256生成token

    try {
    Algorithm algorithm = Algorithm.HMAC256("secret");
    String token = JWT.create()
      .withIssuer("auth0")
      .sign(algorithm);
      //输出令牌
    	System.out.println(token);
    } catch (JWTCreationException exception){
    //Invalid Signing configuration / Couldn't convert Claims.
    }
    
  3. token验证

    String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
    try {
     Algorithm algorithm = Algorithm.HMAC256("secret"); //use more secure key
     JWTVerifier verifier = JWT.require(algorithm)
         .withIssuer("auth0")
         .build(); //Reusable verifier instance
     DecodedJWT jwt = verifier.verify(token);
    } catch (JWTVerificationException exception){
     //Invalid signature/claims
    }
    
  4. 常见的异常信息

    AlgorithmMismatchException 算法不匹配异常

    InvalidClaimException 失效的payload异常

    JWTCreationException jwt创建异常

    JWTDecodeException jwt解码异常

    JWTVerificationException jwt验证异常

    SignatureGenerationException 签名生成异常

    SignatureVerificationException 签名不一致异常

    TokenExpiredException 令牌过期异常

工具类封装

public final class JwtToken {

    /*
     *
     *  JWT的参数说明:
     *  1.withClaim("iss", "Service") 自定义属性,有效负载
     *  2.withNotBefore(new Date()) 生效时间
     *  3.withJWTId(UUID.randomUUID().toString()) 保证唯一
     *  4.withIssuer(ISSUER) 发布者
     *  5.withExpiresAt(expiresAt) 闲置(超期)时间
     *  6.withIssuedAt(iatDate) 签名时间
     *  7.sign(algorithm) 签名
     */

    /**
     * 生成令牌token,默认无失效时间
     * 符合JWT标准,采用HMAC256加密
     *
     * @return 令牌字符串 格式:<br/>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqaXQuY29tLmNuIiwiZXhwIjoxNTg2MzkzOTk5fQ.5qGSr47xYj5UxTU7iIb-VIqc0QDLBPEPfiR11wedWqE
     * @throws IllegalArgumentException 参数异常
     * @throws JWTCreationException Token生成异常
     */
    public static String generateToken() throws JWTCreationException {
        //生成令牌token
        return generateToken(null);
    }

    /**
     * 生成令牌token,允许自定义闲置(超期)时间
     * 符合JWT标准,采用HMAC256加密
     *
     * @param expiresAt 令牌闲置(超期)时间,java.util.Date类型,不建议设置过长
     * @return Token字符串 格式:<br/>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqaXQuY29tLmNuIiwiZXhwIjoxNTg2MzkzOTk5fQ.5qGSr47xYj5UxTU7iIb-VIqc0QDLBPEPfiR11wedWqE
     * @throws JWTDecodeException Token生成异常
     */
    public static String generateToken(Date expiresAt) throws JWTCreationException {
        /*
         * 使用第三方包java-jwt工具包创建
         * 使用我方密钥通过HMAC256算法生成签名,用于验证是否被篡改的依据
         */

        //获取签名算法密钥
        Algorithm algorithm = getAlgorithm();

        //创建token
        JWTCreator.Builder jwtCreatorBuilder = JWT.create()
                // 生效时间
                .withNotBefore(new Date())
                // 保证唯一
                .withJWTId(UUID.randomUUID().toString())
                // 发布者
                .withIssuer(ISSUER);

        // 如果有自定义时间,则设置token的超期时间
        if(expiresAt != null){
            /*
             * 超期时间
             *
             * 注意:
             *  1.JWT的token的过期时间是在生成token的时候设置的,无法修改,要修改只能在生成token的时候修改
             *  2.不能把withExpiresAt当成可伸缩的存活时间,主要使用场景
             */
            jwtCreatorBuilder = jwtCreatorBuilder.withExpiresAt(expiresAt);
        }

        //返回生成的token
        return jwtCreatorBuilder.sign(algorithm);
    }

    /**
     * Token验证,当Token出现异常或超期时抛出JWTVerificationException异常
     *
     * @param token Token字符串,格式:<br/>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqaXQuY29tLmNuIiwiZXhwIjoxNTg2MzkzOTk5fQ.5qGSr47xYj5UxTU7iIb-VIqc0QDLBPEPfiR11wedWqE
     * @return 返回DecodedJWT对象,对象中可获取Token内容
     * @throws JWTVerificationException Token验证未通过抛出异常,业务模块应捕获异常进行判断Token有效性
     */
    public static DecodedJWT verifyToken(String token) throws JWTVerificationException {
        // 使用第三方包java-jwt工具包创建
        // 使用我方密钥通过HMAC256算法生成签名,用于验证是否被篡改的依据

        //获取签名算法密钥
        Algorithm algorithm = getAlgorithm();
        //生成需要验证的token的信息
        JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer(ISSUER)
                .build();
        //验证token签名,如果验证未通过跑出异常
        return verifier.verify(token);
    }

    /**
     * 生成token  添加自定义Claim值
     */
    public static String generateToken(Date expiresAt, Map<String,String> ClaimMap){

        //获取签名算法密钥
        Algorithm algorithm = getAlgorithm();
        //创建jwt builder
        JWTCreator.Builder builder = JWT.create();

        //payload
        ClaimMap.forEach((k,v)->{
            builder.withClaim(k,v);
        });

        //创建token
        JWTCreator.Builder jwtCreatorBuilder = builder
                // 生效时间
                .withNotBefore(new Date())
                // 保证唯一
                .withJWTId(UUID.randomUUID().toString())
                // 发布者
                .withIssuer(ISSUER);

        // 如果有自定义时间,则设置token的超期时间
        if(expiresAt != null){
            /*
             * 超期时间
             *
             * 注意:
             *  1.JWT的token的过期时间是在生成token的时候设置的,无法修改,要修改只能在生成token的时候修改
             *  2.不能把withExpiresAt当成可伸缩的存活时间,主要使用场景
             */
            jwtCreatorBuilder = jwtCreatorBuilder.withExpiresAt(expiresAt);
        }

        //返回生成的token
        return jwtCreatorBuilder.sign(algorithm);
    }
    /**
     * 生成token的签名算法密钥
     * @return 返回token的签名算法密钥
     */
    private static Algorithm getAlgorithm(){
        return  Algorithm.HMAC256(SECRET);
    }

    /**
     * Token 密钥
     */
    private final static String SECRET = "test";
    /**
     * Token 发布机构
     */
    private final static String ISSUER = "test";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孑疋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值