JWT令牌登录校验

以下是基于JWT的登录校验模块化实现方案,分为 JWT工具类登录认证模块拦截器模块配置模块 四大核心模块,代码结构清晰且职责分明。


一、模块划分与职责说明

模块名称职责描述关键类/文件
JWT工具类生成、解析、验证JWT令牌JwtUtils.java
登录认证模块验证用户信息,生成并下发JWT令牌AuthController.java
拦截器模块拦截请求并校验JWT令牌有效性JwtAuthInterceptor.java
配置模块注册拦截器,配置拦截路径和排除路径WebMvcConfig.java

导入相关依赖

<!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- 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>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

二、JWT工具类模块(核心代码)

职责:生成令牌、解析令牌、验证签名和过期时间

1、创建配置文件(application.yml

# application.yml
jwt:
  secret: "my-256-bit-secret-key"  # 建议生成随机256位以上字符串
  expiration: 3600000              # 过期时间(单位:毫秒,此处为1小时)

2.JWT工具类

@Component
public class JwtUtils {
    // 从配置文件中注入密钥和过期时间(避免硬编码)
    @Value("${jwt.secret}")
    private String secretKey;
    @Value("${jwt.expiration}")
    private long expiration;

    /**
     * 生成JWT令牌
     * @param userId 用户唯一标识
     * @param claims 自定义声明(如角色)
     */
    public String generateToken(String userId, Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userId)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
    }

    /**
     * 解析并验证JWT令牌
     */
    public Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 校验令牌是否过期或被篡改
     */
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }
}

三、登录认证模块(伪代码)

职责:验证用户登录信息,返回JWT令牌

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private JwtUtils jwtUtils;

    // 用户已实现的验证逻辑(伪代码)
    @Autowired
    private UserService userService;

    @PostMapping("/login")
    public Result login(@RequestBody LoginRequest request) {
        // 1. 调用用户实现的验证逻辑
        User user = userService.authenticate(request.getUsername(), request.getPassword());
        
        // 2. 生成JWT令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("role", user.getRole()); // 添加角色声明
        String token = jwtUtils.generateToken(user.getId(), claims);
        
        // 3. 返回令牌
        return Result.success("登录成功", token);
    }
}

四、拦截器模块(核心代码)

在这里插入图片描述

职责:拦截请求并校验JWT令牌有效性

这一段拦截器的代码需要了解前端是如何来存储下发的token令牌的然后每次操作需要校验一下这个token是否合法。(下面这个是一个例子)

@Component
public class JwtAuthInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 1. 从请求头提取令牌
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            sendError(response, 401, "未提供有效令牌");
            return false;
        }
        token = token.substring(7); // 去除"Bearer "前缀

        // 2. 校验令牌
        if (!jwtUtils.validateToken(token)) {
            sendError(response, 403, "令牌无效或已过期");
            return false;
        }

        // 3. 解析用户信息并存入请求上下文
        Claims claims = jwtUtils.parseToken(token);
        request.setAttribute("userId", claims.getSubject());
        request.setAttribute("role", claims.get("role"));
        return true;
    }

    // 统一返回错误信息
    private void sendError(HttpServletResponse response, int code, String message) {
        response.setStatus(code);
        response.setContentType("application/json");
        try {
            response.getWriter().write("{\"code\":" + code + ", \"message\":\"" + message + "\"}");
        } catch (IOException ignored) {}
    }
}

五、配置模块(关键配置)

职责:注册拦截器,配置拦截规则

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private JwtAuthInterceptor jwtAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtAuthInterceptor)
            .addPathPatterns("/api/**")      // 拦截所有API请求
            .excludePathPatterns(            // 排除无需校验的路径
                "/auth/login",
                "/swagger-ui/**",
                "/v3/api-docs/**"
            );
    }
}

六、安全增强建议

  1. HTTPS传输:确保生产环境启用HTTPS,防止令牌被窃取。
  2. 密钥管理:将 jwt.secretjwt.expiration 写入配置文件(如 application.yml),避免硬编码。
    jwt:
      secret: "your-256-bit-secret-key"  # 推荐使用256位以上随机字符串
      expiration: 3600000                # 1小时有效期(单位:毫秒)
    
  3. 令牌刷新机制:可结合刷新令牌(Refresh Token)延长会话有效期。
  4. 黑名单机制:在拦截器中校验令牌是否已被主动注销(如通过Redis记录失效令牌)。

七、全局异常处理(可选补充)

若需要在拦截器中触发全局异常处理器,可通过转发请求到Controller层:

// 在拦截器中捕获异常后转发
request.getRequestDispatcher("/error-handler").forward(request, response);

// 定义全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    @RequestMapping("/error-handler")
    public Result handleFilterException(HttpServletRequest request) {
        Exception ex = (Exception) request.getAttribute("filter.error");
        return Result.error(ex.getMessage());
    }
}

通过以上模块化设计,实现了 登录认证 → 令牌下发 → 请求拦截 → 安全校验 的完整链路,各模块职责明确,便于维护和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值