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

在 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 相关依赖:

XML 复制代码
<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。

java 复制代码
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 是否有效。

java 复制代码
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 中注册该拦截器,使其在处理请求之前执行。

java 复制代码
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 并返回给前端。

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 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 合法且有效。

相关推荐
白仑色2 分钟前
java中的anyMatch和allMatch方法
java·linux·windows·anymatch·allmatch
刃神太酷啦4 分钟前
C++ list 容器全解析:从构造到模拟实现的深度探索----《Hello C++ Wrold!》(16)--(C/C++)
java·c语言·c++·qt·算法·leetcode·list
wearegogog1234 分钟前
C# 条码打印程序(一维码 + 二维码)
java·开发语言·c#
码农阿豪4 分钟前
用 PlaylistDL 攒私人音乐库?加个 cpolar,出门在外也能随时听!
java
LaughingDangZi4 分钟前
vue+java分离项目实现微信公众号开发全流程梳理
java·前端·后端
爬山算法6 分钟前
Netty(14)如何处理Netty中的异常和错误?
java·前端·数据库
李慕婉学姐23 分钟前
【开题答辩过程】以《基于Android的健康助手APP的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
android·java·mysql
qq_124987075337 分钟前
基于springboot健康养老APP的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·mysql·微信小程序·毕业设计
张np40 分钟前
java基础-Deque 接口
java·开发语言