java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot JWT Token登录认证

基于SpringBoot+JWT 实现Token登录认证与登录人信息查询功能

作者:柒.梧.

本文给大家介绍基于SpringBoot+JWT实现Token登录认证与登录人信息查询功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值

在前后端分离项目中,传统的Session登录认证已无法满足需求——Session依赖服务器内存存储,分布式部署时会出现认证失效问题,且存在跨域、安全性不足等弊端。而JWT(JSON Web Token)作为一种无状态、轻量级的认证方式,无需在服务器存储会话信息,仅通过客户端携带Token即可完成认证,完美解决上述问题。

本文将基于SpringBoot框架,结合JJWT工具包,完整实现“Token生成→登录认证→Token解析→登录人信息查询”全流程,全程结合可直接复用的代码,拆解每一步核心逻辑,从依赖配置到接口实现,再到避坑指南,覆盖实战开发所有关键要点,新手也能快速上手落地。

核心技术栈:SpringBoot(后端框架)+ JJWT(JWT工具包,简化Token生成与解析)+ SpringMVC(接口开发),无需复杂配置,依赖引入后即可快速开发,代码可直接集成到管理系统、APP后端等各类前后端分离项目中。

一、核心原理:JWT为什么能实现无状态认证?

在讲解代码实现前,先简单理解JWT的核心逻辑,避免只懂代码、不懂原理:

二、前期准备:依赖配置与核心参数配置

实现JWT认证,需先引入JJWT依赖(负责Token的生成、解析和验证),再配置JWT核心参数(密钥、过期时间),这是实现后续功能的基础。

2.1 引入JJWT依赖(pom.xml)

本文使用JJWT 0.11.5版本(稳定版本,兼容SpringBoot 2.x/3.x),需引入3个依赖(api、impl、jackson,分别负责核心API、运行时实现、JSON序列化):

<!-- JWT核心依赖:提供Token生成、解析的API -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<!-- JWT运行时依赖:实现核心API的底层逻辑 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope> <!-- 仅运行时生效,编译时不依赖 -->
</dependency>
<!-- JWT JSON序列化依赖:用于Payload中JSON数据的序列化/反序列化 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

2.2 配置JWT核心参数(application.yml)

将JWT的密钥(secret)和Token过期时间(expiration)配置在配置文件yaml中,避免硬编码,便于后续修改和部署,参数说明如下:

jwt:
  secret: "zxcvbnmlkjhgfdsaqwertyuiop123456" # 自定义密钥,长度≥32位,建议生产环境使用更复杂的密钥
  expiration: 7200 # Token过期时间(秒),7200秒=2小时

三、核心功能实现(结合代码,逐模块拆解)

本文实现3个核心功能,串联起Token登录与信息查询的全流程:1. JWT工具类(Token生成、解析、验证);2. 登录接口(验证用户身份,生成Token并返回);3. 登录人信息查询接口(解析Token,获取用户标识,查询并返回用户信息)。

模块1:JWT工具类(JwtUtil)—— 核心工具

封装JWT的核心操作:生成Token、解析Token获取用户标识、验证Token有效性,该类交给Spring管理(@Component),通过@Value注入配置文件中的参数,可在其他类中直接注入使用。

package com.qcby.aischool.util;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
@Component // 交给Spring管理,支持依赖注入
public class JwtUtil {
    // 从配置文件注入Token过期时间(秒)
    @Value("${jwt.expiration}")
    private long expiration;
    // 从配置文件注入JWT密钥
    @Value("${jwt.secret}")
    private String secret;
    /**
     * 生成Token(核心方法)
     * @param id 存储在Token中的用户标识(如用户ID、用户名,本文用用户ID)
     * @return 生成的JWT Token字符串
     */
    public String generateToken(String id) {
        // 1. 根据密钥生成加密Key(HS256算法要求Key为HmacSHA256类型)
        Key key = Keys.hmacShaKeyFor(secret.getBytes());
        // 2. 构建Token并返回
        return Jwts.builder()
                .setSubject(id) // 设置Payload:存储用户标识(核心信息)
                .setIssuedAt(new Date()) // 设置签发时间(当前时间)
                // 设置过期时间:当前时间 + 过期时间(秒转毫秒)
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
                .signWith(key, SignatureAlgorithm.HS256) // 设置签名算法和密钥
                .compact(); // 生成最终的Token字符串
    }
    /**
     * 解析Token,获取存储在Payload中的用户标识(如用户ID)
     * @param token 客户端传递的Token字符串
     * @return 用户标识(本文返回用户ID)
     */
    public String getUsernameFromToken(String token) {
        // 1. 生成加密Key(与生成Token时的密钥一致)
        Key key = Keys.hmacShaKeyFor(secret.getBytes());
        // 2. 解析Token,获取Payload中的subject(即用户标识)
        return Jwts.parserBuilder()
                .setSigningKey(key) // 设置验证签名的密钥
                .build() // 构建解析器
                .parseClaimsJws(token) // 解析Token(若Token无效,会抛出JwtException)
                .getBody() // 获取Payload部分
                .getSubject(); // 获取subject(用户标识)
    }
    /**
     * 验证Token是否有效(核心方法)
     * @param token 客户端传递的Token字符串
     * @return true:Token有效;false:Token无效(签名错误、已过期、格式错误等)
     */
    public boolean validateToken(String token) {
        try {
            // 1. 生成加密Key
            Key key = Keys.hmacShaKeyFor(secret.getBytes());
            // 2. 解析Token,若解析成功且未过期,则Token有效
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            // 捕获异常:JwtException(Token签名错误、已过期等)、IllegalArgumentException(Token格式错误)
            return false;
        }
    }
}

关键细节与避坑点

模块2:登录接口(login)—— Token生成入口

登录接口是Token生成的入口,核心逻辑:接收客户端提交的用户名/密码,验证用户身份(查询数据库,判断用户名密码是否正确),验证通过后,调用JwtUtil生成Token,将Token返回给客户端,客户端后续请求携带该Token即可完成认证。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController // 标记为控制器,处理HTTP请求
public class LoginController {
    // 注入管理员服务(用于查询数据库,验证用户身份,替换为自己项目中的Service)
    @Autowired
    private AdministratorService administratorService;
    // 注入JWT工具类(用于生成Token)
    @Autowired
    private JwtUtil jwtUtil;
    /**
     * 登录接口(客户端提交用户名/密码,获取Token)
     * @param user 客户端传递的登录信息(包含用户名、密码,封装为Administrator实体类)
     * @return 响应结果(成功返回Token,失败返回错误信息)
     */
    @PostMapping("/login")
    @ResponseBody
    public Result login(@RequestBody Administrator user){
        // 1. 验证用户身份:查询数据库,判断用户名/密码是否正确(实际项目中需加密密码后比对)
        List<Administrator> users = administratorService.login(user);
        // 2. 验证通过(查询到唯一用户),生成Token
        if (users.size() == 1){
            // 获取登录用户的ID,作为Token的Payload(用户标识)
            String userId = users.get(0).getId().toString();
            // 调用JwtUtil生成Token
            String token = jwtUtil.generateToken(userId);
            // 构建响应数据,将Token返回给客户端
            Map<String,String> data = new HashMap<>();
            data.put("token", token);
            // 返回成功响应(Result为自定义响应实体,包含code、msg、data)
            return new Result().success(data);
        }else {
            // 验证失败(未查询到用户或查询到多个用户),返回错误信息
            return new Result().error("用户名或密码错误");
        }
    }
}

核心注意点与优化建议

模块3:登录人信息查询接口(info)—— Token解析与信息查询

客户端登录成功并获取Token后,后续请求(如查询个人信息)需携带Token,服务器通过解析Token获取用户标识,再根据标识查询用户信息并返回。本文中,Token解析逻辑由拦截器完成(代码中未展示拦截器,后续补充),拦截器解析Token后,将用户ID存入request属性中,接口直接从request中获取用户ID即可。

    /**
     * 登录人信息查询接口(需携带Token访问)
     * 前端请求路径:/api/user/info(可根据实际需求修改)
     * @param request 请求对象,用于获取拦截器解析后的用户ID
     * @return 登录人的完整信息(如管理员信息)
     */
    @GetMapping("/info")
    @ResponseBody
    public Result getLoginAdministratorInfo(HttpServletRequest request) {
        System.out.println("进入查询登录人信息的接口");
        // 1. 从request中获取拦截器解析的用户ID(拦截器已验证Token有效性)
        String id = (String) request.getAttribute("id");
        // 2. 根据用户ID查询数据库,获取登录人完整信息
        Administrator administrator = administratorService.findAdministratorById(Integer.valueOf(id));
        // 3. 返回登录人信息
        return Result.success(administrator);
    }

关键补充:Token拦截器(必加,代码补充)

上述接口能直接从request中获取用户ID,核心是Token拦截器——拦截所有需要认证的请求,验证Token有效性,解析Token中的用户ID,存入request属性中。补充拦截器代码(可直接复用):

@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtUtil jwtUtil;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 从Header中获取Token(前端需将Token放在Authorization中)
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7); // 去掉"Bearer "前缀
        }
        // 2. 验证Token
        if (token == null || !jwtUtil.validateToken(token)) {
            response.setStatus(401); // 未授权
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"Token无效或已过期\"}");
            return false;
        }
        // 3. Token有效,将用户ID存入request属性中
        String userId = jwtUtil.getUsernameFromToken(token);
        request.setAttribute("id", userId);
        // 4. 继续处理请求
        return true;
    }
}

拦截器配置(需注册到Spring,让拦截器生效):

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private JwtInterceptor jwtInterceptor;
    // 加自定义拦截器JwtInterceptor,设置拦截规则
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/administrator/login");  
    }
}

拦截器核心逻辑说明

四、完整流程串联与测试步骤

4.1 全流程串联(清晰理解Token的作用)

4.2 测试步骤(快速验证功能,可直接操作)

五、落地优化与避坑指南(实战必备)

上述代码可直接复用,但在实际生产环境中,需注意以下优化点和坑点,避免线上问题,提升系统安全性和稳定性。

5.1 核心优化点

5.2 常见坑点与解决方案

六、总结与扩展

本文基于SpringBoot+JJWT,完整实现了Token登录认证与登录人信息查询功能,核心优势在于:

1. 无状态认证:服务器无需存储会话信息,减轻服务器压力,支持分布式部署,解决传统Session认证的弊端。

2. 代码简洁可复用:JWT工具类、拦截器、接口代码均可直接复用,只需替换实体类和Service,即可快速集成到各类前后端分离项目中。

3. 安全性高:通过密钥签名Token,防止Token被篡改;Payload不存储敏感信息,降低信息泄露风险;拦截器统一拦截,确保接口安全。

扩展方向:

如果在实现过程中遇到问题,可结合JJWT官方文档排查,也可留言交流探讨,助力快速落地JWT认证功能。

到此这篇关于基于SpringBoot+JWT 实现Token登录认证与登录人信息查询功能的文章就介绍到这了,更多相关SpringBoot JWT Token登录认证内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文