基于 JWT 进行身份验证

一、JWT 介绍

JWT 本质上就是一组字串,通过(.)切分成三个为 Base64 编码的部分:

  • Header : 描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型。
  • Payload : 用来存放实际需要传递的数据
  • Signature(签名):服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。

JWT 通常是这样的:xxxxx.yyyyy.zzzzz。

示例:

text 复制代码
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

二、实现代码

1. 添加依赖
java 复制代码
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.19.7</version> <!-- 请检查最新版本 -->
</dependency>
2. 创建JWT工具类

创建一个JWT工具类,用于生成和验证JWT。

java 复制代码
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.time.Duration;
import java.time.Instant;

public class JwtUtil {
    private static final String SECRET_KEY = "yourSecretKey"; // 应使用安全的随机密钥
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET_KEY);

    // 生成JWT
    public static String generateToken(String username) {
        Instant now = Instant.now();
        Instant expiration = now.plus(Duration.ofDays(1)); // 有效期1天

        return JWT.create()
                .withSubject(username)
                .withIssuedAt(Date.from(now))
                .withExpiresAt(Date.from(expiration))
                .sign(ALGORITHM);
    }

    // 解析JWT
    public static DecodedJWT verifyToken(String token) {
        try {
            return JWT.require(ALGORITHM)
                    .build()
                    .verify(token);
        } catch (Exception e) {
            return null; // 返回null表示token无效或已过期
        }
    }

    // 获取JWT中的用户名
    public static String getUsernameFromToken(String token) {
        DecodedJWT decodedJWT = verifyToken(token);
        return decodedJWT != null ? decodedJWT.getSubject() : null;
    }
}
3. 实现登录验证
java 复制代码
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
        // 简化起见,直接生成JWT,实际应用中需要验证用户名和密码
        if (isValidUser(username, password)) { // 假设的验证方法
            String token = JwtUtil.generateToken(username);
            return "Bearer " + token; // 返回JWT给客户端
        } else {
            return "Invalid credentials";
        }
    }

    // 示例:验证JWT并在后续请求中使用
    // 这里只是一个示意,实际中可能需要通过过滤器或拦截器来处理
    @PostMapping("/protectedResource")
    public String protectedResource(@RequestHeader("Authorization") String authorizationHeader) {
        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            String token = authorizationHeader.substring(7); // 去除"Bearer "前缀
            String username = JwtUtil.getUsernameFromToken(token);
            if (username != null) {
                return "Hello, " + username;
            }
        }
        return "Unauthorized";
    }
}

三、注意事项

注意事项:

  1. 密钥安全:JWT的签名密钥(secret key)是验证JWT真伪的关键。必须确保密钥的安全存储,防止泄露,因为一旦密钥被破解,攻击者就能伪造任意JWT。JWT 安全的核心在于签名,签名安全的核心在密钥。
  2. 过期时间管理:JWT通常包含过期时间(expiration time),以防止无限期的有效性。合理设置过期时间,并处理好刷新令牌(refresh tokens)的逻辑,以平衡安全性与用户体验。
  3. 令牌存储:客户端通常将JWT存储在本地(如LocalStorage或Cookie中),这要求客户端环境的安全性,防止XSS和CSRF攻击。
  4. 令牌泄漏:一旦JWT发出,除非使用黑名单机制,否则无法撤销。如果JWT被盗,直到其过期前都可能被滥用。
  5. 负载大小:JWT的有效载荷(payload)携带用户信息,过大的载荷会导致较大的网络开销和解析时间。
  6. 无状态性:JWT的无状态特性简化了服务端架构,但也意味着每次验证都要解析JWT,可能影响性能,尤其是在频繁验证的场景下。

弊端:

  1. 不可撤销性:JWT一旦签发,除非设置很短的有效期,否则一旦泄露,很难立即阻止其访问权限,不像传统的session可以在服务器端立即失效。
  2. 令牌管理:长生命周期的JWT可能需要引入刷新令牌机制,这增加了实现的复杂度,同时也需要妥善处理刷新令牌的安全问题。
  3. 性能影响:JWT的验证需要进行签名验证,对于大流量应用,频繁的JWT验证可能会成为性能瓶颈,尤其是当JWT包含大量声明时。
  4. 信息泄露风险:JWT的payload是Base64编码的,虽然不是直接可读,但容易解码。如果JWT包含敏感信息,可能增加信息泄露的风险。
  5. 扩展性挑战:在分布式系统中,所有节点都需要能够验证JWT,这意味着密钥需要同步,或者采用公钥/私钥对的方案,增加了运维的复杂度。

----->>>>>>JWT 身份认证优缺点分析,为什么可以有效避免了 CSRF 攻击?

相关推荐
szephyr5 天前
前端鉴权实战:Token 存哪、怎么刷新、怎么防 XSS 与 CSRF
鉴权·xss·csrf·jwt·token
2601_9622972515 天前
Authlib 0.13通用Python认证授权库wheel安装包(支持Python 2/3)
python·jwt·oauth2.0·authlib·openidconnect
山甫aa17 天前
【从零开始的 Web 后端学习】令牌技术一篇搞定(JWT 登录认证保姆级)
后端·学习·spring·web·jwt
FungLeo17 天前
成为全栈·Node 后端篇·认证方案:JWT 还是 Session
node.js·jwt·session·认证方案
Looooking20 天前
Python 之 jwt 令牌生成和校验
python·jwt
侧耳倾听11125 天前
jwt使用简介
java·jwt
yuyuyui1 个月前
DOTNET 鉴权系列- JWT 会话撤销与主动登出
jwt·.net core·token·主动登出·会话撤销
正儿八经的少年1 个月前
sa-token,jwt,security 生成 token 的区别
sa-token·security·jwt
FungLeo1 个月前
Node 后端实战 · JWT 双密钥轮转与 token 版本号:多租户 SaaS 如何不停机换密钥、一键踢全设备
jwt·长短 token·无感刷新 token·jose·hs256