Spring使用JWT进行登录验证

前情提要:由于这学期课设需要使用SSM技术栈,导致一些好用的登录框架无法适配,所以改用手写JWT进行登录验证

JWT 简介

JSON Web Token (JWT) 是一种用于在网络应用环境中进行用户身份验证和信息交换的开放标准。它通过将数据以 JSON 格式进行编码,使得信息在不同的系统和应用之间得以安全传递。JWT 的主要特点是结构简洁且安全性高,广泛应用于单点登录(SSO)、API 授权和用户身份认证。

JWT 由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部通常包括令牌的类型(JWT)和所使用的签名算法。载荷部分包含实际传输的用户信息或声明,而签名则用于验证信息的完整性以及确保该信息未被篡改。

JWT 的无状态特性使得它在分布式应用中尤为高效,避免了传统基于会话的认证机制中服务器存储会话状态的复杂性。我们这次手动实现它。
首先引入JWT

<dependency>
      <groupId>io.jsonwebtokengroupId>
      <artifactId>jjwt-apiartifactId>
      <version>0.11.5version>
    dependency>
    <dependency>
      <groupId>io.jsonwebtokengroupId>
      <artifactId>jjwt-implartifactId>
      <version>0.11.5version>
      <scope>runtimescope>
    dependency>
    <dependency>
      <groupId>io.jsonwebtokengroupId>
      <artifactId>jjwt-jacksonartifactId>
      <version>0.11.5version>
      <scope>runtimescope>
    dependency>

编写JWT工具类

@Component
public class JwtUtil {

    private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    private static final long EXPIRATION_TIME = 864_000_000; // 10 天

    // 生成 JWT
    public static String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username) // 设置主题(通常是用户名或用户ID)
                .setIssuedAt(new Date()) // 设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 设置过期时间
                .signWith(SECRET_KEY) // 使用密钥签名
                .compact();
    }

    // 从 JWT 中提取用户名
    public static String getUsernameFromToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(SECRET_KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }

    // 验证 JWT 是否有效
    public static boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(SECRET_KEY)
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    public static Long getUserId(String authorizationHeader){
        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
            return 0L;
        }

        // 提取 JWT
        String token = authorizationHeader.substring(7); // 去掉 "Bearer " 前缀

        // 验证 JWT 是否有效
        if (!JwtUtil.validateToken(token)) {
            return 0L;
        }

        // 从 JWT 中提取用户名
        String username = JwtUtil.getUsernameFromToken(token);
        return Long.valueOf(username);
    }
}

实现了以后还要编写并注册拦截器

public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 登录成功应该有session(在登陆的Controller中设置session)
        String token = request.getHeader("Authorization");

        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7); // 去掉 "Bearer " 前缀
            if (JwtUtil.validateToken(token)) {
                // 如果 JWT 有效,继续处理请求
                return true;
            } else {
                // 如果 JWT 无效,返回 401 未授权
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                return false;
            }
        } else {
            // 如果没有 JWT,返回 401 未授权
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
    }
}


将拦截器注册

spring-mvc.xml

 <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/user/login"/>
            <mvc:exclude-mapping path="/user/register"/>
            <bean class="com.paoxiaomo.javaee.config.LoginHandlerInterceptor"/>
        mvc:interceptor>
    mvc:interceptors>

然后我们就可以在进行登录的时候使用它了

@RequestMapping("/login")
    public ResponseEntity<Map<String, String>> login(@RequestBody UserDto userDto) {
        UserEntity user=userService.getUserByUsername(userDto.getUsername());
        // 验证用户名和密码
        if (PasswordEncryptionUtil.matches(userDto.getPassword(), user.getPassword())) {
            // 生成 JWT
            String token = JwtUtil.generateToken(user.getId().toString());
            return new ResponseEntity<>(Map.of("token",token), HttpStatus.OK);
        }
        return new ResponseEntity<>(Map.of("token","Invalid"), HttpStatus.UNAUTHORIZED);
    }

运行结果:-
Spring使用JWT进行登录验证_第1张图片

你可能感兴趣的:(Java后端,spring,java,后端)