JWT令牌

一.介绍

在当今的Web开发中,安全认证和授权变得尤为重要。JWT(全称JSON Web Token)是一个开放的行业标准(RFC 7519),用于客户端和服务器之间传递安全可靠的信息,本质上是一个token(token表示令牌,本质上为字符串),是一种紧凑的URL安全方法

二.JWT的组成

JWT由三部分组成,每个部分中间使用(.)分割,例如aa.bb.cc

  • Header(头部):头部包括令牌的类型(即JWT)以及使用的哈希算法(如HMAC SHA256或RSA)
  • Payload(负载):负载部分是存放有效信息的地方,里面是一些自定义内容,比如用户ID,用户名等,也可以存放JWT提供的现场字段,比如过期时间戳EXP等
  • Signature(签名):签名部分用于防止JWT内容被篡改,当签名部分中任何一个字符被篡改,整个令牌都会校验失败,很大程度上确保了JWT令牌的安全性
    在这里插入图片描述

三.JWT的常见应用

在企业开发中,JWT令牌多被用于解决会话跟踪(例如登录认证),其流程可以简单描述为如下步骤:

  • 服务器具备生成令牌和验证令牌的能力
  • 用户登录请求,经过负载均衡,把请求转给了第一台服务器,第一台服务器进行账号密码验证,验证成功后,生成一个令牌,并返回给客户端
  • 客户端收到令牌之后,把令牌存储起来,可以存储在Cookie中,或者也可以存储在其他存储空间中(如localStorage)
  • 用户登录成功之后,携带令牌进一步操作,此时请求转发到了第二台服务器,第二台服务器会先进行权限验证操作,验证令牌是否有效,如果有效就说明用户已经执行了登录操作,反之如果令牌无效说明用户未执行登录操作
    在这里插入图片描述

四.JWT的优缺点

优点:

  • 解决了集群环境下的认证问题
  • 减轻服务器的存储压力(无需在服务器端存储)

缺点:

  • 需要自己实现令牌的生成,传递和校验

五.JWT的使用

1.引入依赖

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

2.生成密钥

import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.security.Key;
@SpringBootTest
public class JWTTest {
    @Test
    public void test(){
        // 使用HS256签名算法创建一个密钥对象
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        // 将密钥编码为Base64字符串
        String secretString = Encoders.BASE64.encode(key.getEncoded());
        System.out.println(secretString);
    }
}

3.JWT工具包实现

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JwtUtil {
    
    /**
     * expiration 过期时间 (ms)
     * secretString Base64编码的密钥(上述测试方法随机生成的密钥)
     * key 解码secretString生成的HMAC SHA密钥
     */
    private static long expiration = 60 * 60 * 1000;

    private static String secretString = "WPSZRvzliySfPi1vb/LOdqOPJD0EdQRPnstMiVako6o=";

    private static Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretString));

    /**
     * 生成JWT令牌
     * @param claim
     * @return
     */
    public static String generateJwt(Map<String, Object> claim) {
        String jwt = Jwts.builder()
                .setClaims(claim)  // 自定义内容(载荷)
                .setIssuedAt(new Date()) // 设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + expiration)) // 设置过期时间
                .signWith(key) // 签名算法
                .compact();
        return jwt;
    }
    
    /**
     * 验证JWT令牌
     * @param jwt
     * @return
     */
    public static Claims verifyJwt(String jwt) {
        if (!StringUtils.hasText(jwt)) {
            return null;
        }
        JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();
        Claims body = null;
        try {
            // 解析token
            body = build.parseClaimsJws(jwt).getBody();
        } catch (ExpiredJwtException e) { //令牌过期
            log.error("令牌过期");
        } catch (SignatureException e) { //令牌错误(伪造)
            log.error("令牌错误(伪造)");
        } catch (MalformedJwtException e) { //不存在令牌
            log.error("未查找到令牌");
        }
        return body;
    }

    /**
     * 从jwt中获取对应字段(如id)
     * @param jwt
     * @return
     */
    public static Integer getIdFromToken(String jwt) {
        Claims claims = verifyJwt(jwt);
        if (claims == null) {
            log.error("Jwt令牌错误");
            return null;
        }
        Map<String,Object> map = new HashMap<>(claims);
        return (Integer) map.get("id");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值