jwt权限验证原理

1. JWT,全称是Json Web Token, 是一种JSON风格的轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权!

 2. JWT 由三部分组成:

  • 头部(Header): 通常包含令牌的类型(即 JWT)和加密算法(如 HMAC SHA256 或 RSA)。例如:        
{
  "alg": "HS256",
  "typ": "JWT"
}
  • 载荷(Payload): 包含要传递的声明(Claims)。声明总共可以包括如下七项,但是不是必须全部包含,可以根据业务具体需要进行设置。如下。       
{
 iss: jwt签发者
sub: jwt所面向,使用jwt的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须大于签发时间
nbf: 定义在指定时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
}

3.  签名(Signature): 通过对头部和载荷进行编码,然后用指定的算法和密钥生成的签名,用于验证数据的完整性和真实性,其中secret是密钥,不可泄漏,并且其生成也用到了头部信息和载荷信息。例如:

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

JWT 的这三部分通过点(.)连接在一起形成最终的 JWT。例如:eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsICJuYW1lIjogIkpvaG4gRG9lIiwgImFkbWluIjogdHJ1ZX0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

4.校验流程:

  • 生成 JWT: 服务器在用户登录时生成 JWT。生成时,服务器将用户的身份信息(例如用户 ID 和角色)放入载荷中,并用密钥对其进行签名,生成完整的 JWT。

  • 传递 JWT: JWT 可以通过 HTTP 请求的头部、查询参数或 cookies 进行传递。常见的做法是将 JWT 放在 Authorization 头部中,如 Authorization: Bearer <token>

  • 验证 JWT: 服务器在收到请求时,解码 JWT 头部和载荷,使用密钥验证签名是否正确。如果签名验证成功且载荷中的信息有效(例如,未过期),则接受请求;否则拒绝请求。

5.代码示例,工具类      

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
 
import java.util.Date;
import java.util.concurrent.TimeUnit;
 
@Component
public class JwtUtils {
 
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
 
 
    @Value("${jwt.secret}")
    private String secret;
 
    @Value("${jwt.expiration}")
    private  long expiration;
 
    /**
     * 生成token
     * @param username
     * @return
     */
    public  String generateToken(String username) {
        String token = Jwts.builder()
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
 
        // 将 Token 存储到 Redis 中
        redisTemplate.opsForValue().set(username, token, expiration, TimeUnit.MILLISECONDS);
 
        return token;
    }
 
    /**
     * 验证token
     * @param token
     * @return
     */
    public boolean validateToken(String token) {
        // 从 Token 中获取用户名
        String username = getUsernameFromToken(token);
 
        // 从 Redis 中获取存储的 Token
        String storedToken = redisTemplate.opsForValue().get(username);
 
        // 判断 Redis 中存储的 Token 是否与传入的 Token 相同
        return storedToken != null && storedToken.equals(token);
    }
 
    /**
     * 删除token
     * @param username
     */
    public void removeToken(String username) {
        // 从 Redis 中删除 Token
        redisTemplate.delete(username);
    }
 
    /**
     * 根据token获取用户信息
     * @param token
     * @return
     */
    public String getUsernameFromToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return claims.getSubject();
    }
 
    /**
     * 判断token是否存在
     * @param username
     * @return
     */
    public String getTokenIfExists(String username) {
        // Check if a valid token exists in Redis for the given username
        String storedToken = redisTemplate.opsForValue().get(username);
 
        // Validate the stored token
        if (storedToken != null && validateToken(storedToken)) {
            return storedToken;
        } else {
            return null;
        }
    }
 
 
}

6. 优缺点。jwt是无状态,自包含式(自身包含了加密算法以及加密数据)的权限校验框架。可以不同于session,使得可以不依赖于服务端的数据,减轻了服务的的负担,并且前端可以不用考虑请求被分发到哪一台服务器。

     缺点在于。生成的token很长,且都所有请求都比带上,增加网络传输开销;过期时间不可控,一旦生成了之后,比如用户注销登陆,token仍然是有效的,除非另外开发这部分过期功能。令牌中包含了用户信息,如果令牌被盗取,攻击者可以获得用户的敏感信息,因此需要对令牌进行严格的存储和管理。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值