【spring】集成JWT实现登录验证

发布于:2025-02-10 ⋅ 阅读:(79) ⋅ 点赞:(0)

在 Spring 应用中,使用 JSON Web Token (JWT) 是一种常见的认证和授权机制。JWT 是一种基于 JSON 的开放标准 (RFC 7519),用来在各方之间传递安全、可信的数据。以下是如何在 Spring 框架中集成和使用 JWT 的完整指南。


核心概念

  1. JWT 结构

    • Header:包含类型和签名算法信息。
    • Payload:包含声明 (claims),如用户信息、角色等。
    • Signature:用来验证 token 的完整性,通常使用 HMAC 或 RSA 等算法。
  2. 使用场景

    • 用户登录后,服务端生成 JWT 并返回给客户端。
    • 客户端将 JWT 存储在本地(如浏览器的 LocalStorage 或 HttpOnly Cookie 中)。
    • 客户端每次请求时,将 JWT 添加到请求头中,服务端验证后授权访问。

JWT 的使用通常分为以下几个步骤:

  1. 用户通过用户名和密码登录,后端验证用户身份。
  2. 后端生成 JWT(包含用户的相关信息),并将其返回给前端。
  3. 前端存储该 JWT(一般存储在 LocalStorage 或 Cookie 中)。
  4. 后续每次请求,前端都会将该 JWT 放入请求头的 Authorization 字段中,后端验证 JWT 的合法性。
  5. 后端根据 JWT 中的内容进行相应的认证和授权。

集成步骤

以下是 Spring Boot 项目中使用 JWT 的主要步骤:

1. 添加依赖

pom.xml 中添加 JWT 相关依赖:

<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>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
</dependency>
1. 创建 JWT 工具类

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

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {

    private static final String SECRET_KEY = "your_secret_key"; // 密钥
    // 生成安全密钥
    private final static SecretKey secretKey =
            Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET_KEY));
    // 过期时间(单位:毫秒)
    private static final long EXPIRATION = 3600000; // 一小时

    // 生成JWT
    public static String generateToken(String username, Integer id) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", username); // 可以根据需要加入更多的自定义字段
        claims.put("userId", id);

        return Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) // 过期时间1小时
                .signWith(secretKey) // 签名
                .compact();
    }

    // 解析JWT
    public static Claims parseToken(String token) throws JwtException {
        try {
            JwtParserBuilder jwtParserBuilder = Jwts.parserBuilder().setSigningKey(secretKey);
            return jwtParserBuilder
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (JwtException e) {
            // 捕获解析异常,抛出一个自定义的异常或返回null
            throw new JwtException("Invalid token: " + e.getMessage(), e);
        }
    }

    // 检查JWT是否有效
    public static boolean isTokenExpired(String token) {
        try {
            Claims claims = parseToken(token);
            return claims.getExpiration().before(new Date());
        } catch (JwtException e) {
            // 解析失败,视为Token无效
            return true;
        }
    }

    // 获取用户名
    public static String getUsername(String token) {
        try {
            Claims claims = parseToken(token);
            return claims != null ? claims.get("username", String.class) : null;
        } catch (JwtException e) {
            // Token无效,返回null或可以选择抛出异常
            return null;
        }
    }

    // 获取用户id
    public static Integer getUserId(String token) {
        try {
            Claims claims = parseToken(token);
            return claims != null ? claims.get("userId", Integer.class) : null;
        } catch (JwtException e) {
            // Token无效,返回null或可以选择抛出异常
            return null;
        }
    }
}
2. 创建 JWT 拦截器

接下来,创建一个 HandlerInterceptor 实现 JWT 登录验证逻辑。这个拦截器会在每次请求时验证请求头中的 JWT 是否有效。

import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("Authorization");

        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: No token provided");
            return false;
        }

        token = token.substring(7); // 去掉 "Bearer " 前缀

        if (JwtUtil.isTokenExpired(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: Token expired");
            return false;
        }

        String username = JwtUtil.getUsername(token);
        if (username == null) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: Invalid token");
            return false;
        }

        // 将用户名或用户信息放入请求属性中,后续处理可以使用
        request.setAttribute("username", username);

        return true; // 继续执行请求
    }
}
3. 配置拦截器

WebMvcConfigurer 中注册该拦截器,使其在处理请求之前执行。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtInterceptor())
                .addPathPatterns("/**") // 所有路径都需要拦截
                .excludePathPatterns("/login", "/register"); // 排除登录和注册等不需要JWT验证的路径
    }
}
4. 创建登录接口

最后,创建一个登录接口用于用户认证,验证成功后生成 JWT 并返回给前端。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        // 在这里根据实际情况验证用户名和密码
        if ("user".equals(username) && "password".equals(password)) {
            // 生成 JWT
            String token = JwtUtil.generateToken(username);
            return "Bearer " + token; // 返回JWT
        }
        return "Invalid credentials"; // 登录失败
    }
}

总结

  1. 创建了一个 JwtUtil 工具类,用于生成、解析和验证 JWT。
  2. 创建了一个 JwtInterceptor 拦截器,在每次请求时验证 JWT 的有效性。
  3. 使用 WebMvcConfigurer 配置了该拦截器,并指定哪些路径需要拦截。
  4. 创建了一个登录接口,用户登录时通过用户名和密码获取 JWT。

通过这些步骤,你就可以使用 JWT 实现一个基本的登录验证功能,并且在 Spring 应用中通过拦截器进行保护,确保请求中的 JWT 合法且有效。


网站公告

今日签到

点亮在社区的每一天
去签到