一文读懂JWT认证含使用教程

1、JWT是什么

JWT是“JSON Web Token”的简写,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于作为JSON对象在各方之间安全的传递信息。此信息是经过数字签名的,因此可以验证和信任。特别适用于分布式站点的单点登录(SSO)场景。

JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。官方网站:https://jwt.io/

2、JWT相比传统Session认证的优势

传统的session认证:

(1)客户端向服务器发送用户名、密码等认证信息。

(2)服务器通过验证后,服务器端生成一个sessionId返回给客户端,并将sessionId保存起来 

(3)客户端自动把返回的sessionId存储在cookie中。

(4)后续客户端没发一次请求,都会在请求头携带cookie,将sessioId传给服务端。

       (5)服务器检查sessionId是否存在,如果存在执行相关业务。

存在的问题:

(1)每个用户信息都存储在服务端,随着用户量的增加,服务器的开销会增大。

(2)session 存储在服务端中,在分布式系统中,这种方式将会失效,为了保证各个服务器中的 session存储的信息一致,需要引入额外的中间件,比如:redis 等

(3)对于非浏览器客户端不适用,原因在于 session 依赖 cookie,移动端没有 cookie

(4)不安全,session 基于 cookie ,如果 cookie 信息被截获,很容易进行 CSRF(跨域请求伪造攻击)

3、JWT认证流程

4、JWT的优势

(1)不占用服务器资源:服务器只需要通过 JWT 工具进行校验即可。

(2)适用于分布式服务:由于JWT不依赖于session和 cookie,只需在客户端访问时请求头携带即可,然后服务器端JWT 令牌进行统一校验。

(3)信息安全:由于签名是使用 标头 和 有效负载 计算的,因此还可以验证内容是否遭到篡改。

(4)支持多种语言:Token 是以 JSON 加密的形式保存在客户端的. 原则上任何 web 都支持。

(5)可防止 XSS和XSRF 因为JWT放入Http Header中的Authorization 位。

(6)跨域访问:JWT包含了完整的认证和授权信息,因此可以轻松的在多个域之间进行传递和使用,实现跨域授权。

5、JWT的结构

JWT 令牌由三个部分组成,分别是 标头(Header)、有效载荷(Payload)、签名(Signature),并且由 "." 分割。类似于 xxxx.yyyy.zzzzz ,也就是 Header.Payload.Signature。

第一部分:标头Header

标头通常由两个部分组成,分别是 令牌的类型(例如 JWT) 和 所使用的签名算法.(例如HMAC、SHA256、RSA.  一般就是用 HS 256 即可。

     例如:

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

然后,这个JSON被Base64编码,以形成JWT的第一部分。

第二部分:有效载荷 Payload

我们传输的一些参数和自定义信息可以放到这里

例如:

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

然后对有效载荷进行Base64编码,以形成JSON Web令牌的第二部分。

第三部分:签名 Signature

Signatrue 需要使用 Base64 编码后的 header 和 payload 以及提供的密钥(私钥),然后使用 header 中指定的签名算法(HS256)构建一个签名,保证 JWT 没有被篡改过。

例如,如果要使用HMAC SHA256算法,则将以以下方式创建签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)
JWT使用
1、pom.xml 引入JWT依赖
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>
 2、生成JWT

@Test
public void createJwt(){
    //设置令牌的过期时间为 100 s
    Calendar instance = Calendar.getInstance();
    instance.add(Calendar.SECOND, 100);
    //创建 Token
    String token = JWT.create()
            .withClaim("id", 6) //payload
            .withClaim("name", "mkj") //payload
            .withExpiresAt(instance.getTime()) //设置过期时间
            .sign(Algorithm.HMAC256("mkj&*&(666*T*"));//签名(这里自定义密钥即可)

    System.out.println(token);
}

3、验证JWT

@Test
public void verifyJwt(){
    //创建验证对象
    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("mkj&*&(666*T*")).build();
    //验证Token(验证失败,会引发异常)
    DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibWtqIiwiaWQiOjYsImV4cCI6MTcxNDk4NTkwM30.YrAcA_mLyI86MRpya2-EGl4vtxFbL2UNYSvCmQ15LqM");

    System.out.println(verify.getClaim("id").asInt());
    System.out.println(verify.getClaim("name").asString());
}

 

验证失败会抛出异常

4、最后封装JWT工具类

package com.rhjt.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

/**
 * @author: mkj
 * @Date 2024/5/6 16:58
 */
public class JwtUtils {
    //自定义密钥
    private static final String SIGN = "mkj&*&(666*T*";

    /**
     * 生成 Token
     * @param map 自定义的载荷数据
     * @return 返回 Token
     */
    public static String createToken(Map<String, String> map) {
        //1.设置过期时间(默认 1 天过期)
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 1);

        //2.创建 jwt builder,添加自定义的载荷数据
        JWTCreator.Builder builder = JWT.create();
        for(Map.Entry<String, String> entry : map.entrySet()) {
            builder.withClaim(entry.getKey(), entry.getValue());
        }
        //3.生成 Token
        String token = builder.withExpiresAt(instance.getTime()) //过期时间
                .sign(Algorithm.HMAC256(SIGN));// sign
        return token;
    }

    /**
     * 验证 Token 合法性
     * @param token
     */
    public static boolean checkToken(String token) {
        try {
            JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取 Token 信息
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token) {
        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
        return verify;
    }
}

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

missterzy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值