SpringBoot 实现 JWT 认证完整方案

2025-12-04 0 593

SpringBoot 实现 JWT 认证完整方案

JWT(JSON Web Token)是一种用于在网络应用间安全传递信息的开放标准,特别适合分布式系统的身份验证。下面我将详细介绍如何在SpringBoot项目中实现JWT认证。

一、JWT 基础概念

JWT由三部分组成,用.连接:

  1. Header(头部):包含令牌类型和使用的加密算法
  2. Payload(载荷):包含用户信息和声明
  3. Signature(签名):使用密钥对前两部分进行签名,确保信息不被篡改

二、项目准备

1. 添加依赖

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


<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.19.2</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

2. 配置文件

application.yml中添加JWT相关配置:

spring:
  application:
    name: springboot-jwt-demo

jwt:
  # 密钥
  secret: your-secret-key-change-in-production
  # 过期时间(毫秒)
  expire-time: 86400000
  # 请求头中Token的名称
  header: Authorization
  # Token前缀
  token-prefix: Bearer

三、核心代码实现

1. JWT工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Map;

@Component
public class JWTUtil {
    
    @Value(\"${jwt.secret}\")
    private String secret;
    
    @Value(\"${jwt.expire-time}\")
    private long expireTime;
    
    /**
     * 生成Token
     * @param claims 要存储在Token中的信息
     * @return 生成的Token字符串
     */
    public String generateToken(Map claims) {
        // 设置过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.MILLISECOND, (int) expireTime);
        
        // 创建JWT Builder
        JWTCreator.Builder builder = JWT.create();
        
        // 添加载荷
        claims.forEach(builder::withClaim);
        
        // 设置签名和过期时间,生成Token
        return builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(secret));
    }
    
    /**
     * 验证Token
     * @param token 要验证的Token
     * @return 验证后的DecodedJWT对象
     * @throws JWTVerificationException 验证失败时抛出异常
     */
    public DecodedJWT verifyToken(String token) {
        return JWT.require(Algorithm.HMAC256(secret))
                .build()
                .verify(token);
    }
    
    /**
     * 解析Token
     * @param token 要解析的Token
     * @return 解析后的DecodedJWT对象
     */
    public DecodedJWT parseToken(String token) {
        return JWT.decode(token);
    }
    
    /**
     * 从Token中获取指定的Claim
     * @param token Token字符串
     * @param claimName Claim名称
     * @return Claim值
     */
    public String getClaim(String token, String claimName) {
        DecodedJWT decodedJWT = parseToken(token);
        return decodedJWT.getClaim(claimName).asString();
    }
}

2. JWT拦截器

import com.auth0.jwt.exceptions.JWTVerificationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

@Component
@Slf4j
public class JWTInterceptor implements HandlerInterceptor {
    
    @Autowired
    private JWTUtil jwtUtil;
    
    @Value(\"${jwt.header}\")
    private String jwtHeader;
    
    @Value(\"${jwt.token-prefix}\")
    private String tokenPrefix;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader(jwtHeader);
        
        // 检查请求头中是否包含Token
        if (token == null || \"\".equals(token.trim())) {
            response401(response, \"Token不存在\");
            return false;
        }
        
        // 移除Token前缀
        if (token.startsWith(tokenPrefix)) {
            token = token.replace(tokenPrefix, \"\").trim();
        } else {
            response401(response, \"Token格式错误\");
            return false;
        }
        
        try {
            // 验证Token
            jwtUtil.verifyToken(token);
            log.info(\"Token验证成功\");
            return true;
        } catch (JWTVerificationException e) {
            log.error(\"Token验证失败: {}\", e.getMessage());
            response401(response, \"Token无效或已过期\");
            return false;
        }
    }
    
    /**
     * 返回401错误响应
     */
    private void response401(HttpServletResponse response, String message) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setCharacterEncoding(\"UTF-8\");
        response.setContentType(\"application/json; charset=utf-8\");
        
        try (PrintWriter out = response.getWriter()) {
            out.append(\"{\"code\": 401, \"message\": \"\").append(message).append(\"\"}\");
        } catch (Exception e) {
            log.error(\"响应错误: {}\", e.getMessage());
        }
    }
}

3. 拦截器配置

import org.springframework.beans.factory.annotation.Autowired;
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 InterceptorConfig implements WebMvcConfigurer {
    
    @Autowired
    private JWTInterceptor jwtInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加拦截器,拦截需要认证的路径
        registry.addInterceptor(jwtInterceptor)
                // 需要拦截的路径
                .addPathPatterns(\"/api/**\")
                // 排除不需要拦截的路径
                .excludePathPatterns(\"/api/login\", \"/api/register\", \"/error\");
    }
}

4. 实体类

import lombok.Data;

@Data
public class LoginRequest {
    private String username;
    private String password;
}

@Data
public class LoginResponse {
    private String token;
    private String username;
    private String message;
}

5. 用户服务接口

public interface UserService {
    boolean login(String username, String password);
    boolean register(String username, String password);
}

6. 用户服务实现

import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class UserServiceImpl implements UserService {
    
    // 模拟数据库,实际项目中应使用数据库存储
    private final Map userMap = new HashMap();
    
    public UserServiceImpl() {
        // 初始化测试用户
        userMap.put(\"admin\", \"123456\");
    }
    
    @Override
    public boolean login(String username, String password) {
        return userMap.containsKey(username) && userMap.get(username).equals(password);
    }
    
    @Override
    public boolean register(String username, String password) {
        if (userMap.containsKey(username)) {
            return false; // 用户名已存在
        }
        userMap.put(username, password);
        return true;
    }
}

7. 登录控制器

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping(\"/api\")
public class AuthController {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private JWTUtil jwtUtil;
    
    @Value(\"${jwt.token-prefix}\")
    private String tokenPrefix;
    
    /**
     * 用户登录
     */
    @PostMapping(\"/login\")
    public ResponseEntity login(@RequestBody LoginRequest request) {
        if (userService.login(request.getUsername(), request.getPassword())) {
            // 构建Token中的载荷信息
            Map claims = new HashMap();
            claims.put(\"username\", request.getUsername());
            
            // 生成Token
            String token = jwtUtil.generateToken(claims);
            
            // 构建响应
            LoginResponse response = new LoginResponse();
            response.setToken(tokenPrefix + \" \" + token);
            response.setUsername(request.getUsername());
            response.setMessage(\"登录成功\");
            
            return ResponseEntity.ok(response);
        }
        return ResponseEntity.badRequest().body(\"用户名或密码错误\");
    }
    
    /**
     * 用户注册
     */
    @PostMapping(\"/register\")
    public ResponseEntity register(@RequestBody LoginRequest request) {
        if (userService.register(request.getUsername(), request.getPassword())) {
            return ResponseEntity.ok(\"注册成功\");
        }
        return ResponseEntity.badRequest().body(\"用户名已存在\");
    }
    
    /**
     * 测试接口,需要验证Token
     */
    @GetMapping(\"/test\")
    public ResponseEntity test() {
        return ResponseEntity.ok(\"访问成功,Token有效\");
    }
}

四、安全性考虑

  1. 密钥安全:密钥必须保密,生产环境应使用强密钥
  2. Token过期时间:设置合理的过期时间,避免永久有效
  3. HTTPS传输:在生产环境中使用HTTPS传输Token
  4. 防XSS攻击:Token存储在localStorage时可能被XSS攻击窃取
  5. Token刷新机制:实现Token刷新机制,避免频繁登录
  6. 黑名单机制:对于已注销的Token,添加到黑名单中

五、优化建议

  1. 使用Redis存储Token:可以更灵活地管理Token生命周期
  2. 实现Refresh Token:提供长期的Refresh Token用于获取新的Access Token
  3. 增加角色权限:在Token中添加用户角色信息,实现更细粒度的权限控制
  4. 使用非对称加密:生产环境可考虑使用RSA等非对称加密算法
  5. 添加IP绑定:在Token中绑定用户IP,增加安全性
  6. 添加日志记录:记录Token的生成、验证和使用情况

六、测试方法

  1. 启动SpringBoot应用
  2. 使用Postman或其他工具测试登录接口:POST http://localhost:8080/api/login
  3. 在请求体中添加用户名和密码
  4. 成功后将返回的Token添加到请求头
  5. 访问需要认证的接口:GET http://localhost:8080/api/test

这个实现提供了SpringBoot中JWT认证的完整流程,包括Token生成、验证和拦截器实现。您可以根据实际需求进行调整和扩展。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 SpringBoot 实现 JWT 认证完整方案 https://www.zuozi.net/3293.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务