当前位置: 代码网 > it编程>编程语言>Java > 基于SpringBoot+JWT 实现Token登录认证与登录人信息查询功能

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

2026年03月03日 Java 我要评论
在前后端分离项目中,传统的session登录认证已无法满足需求——session依赖服务器内存存储,分布式部署时会出现认证失效问题,且存在跨域、安全性不足等弊端。而jwt(js

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

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

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

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

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

  • jwt结构:由三部分组成(header+payload+signature),通过base64编码和签名拼接而成,整体为一串字符串,可直接在http请求头中携带。
    • header(头部):指定签名算法(如hs256)和token类型,base64编码后不可加密(仅编码,非加密)。
    • payload(载荷):存储核心业务信息(如用户id、用户名),可设置过期时间,同样是base64编码(注意:payload不加密,不可存储敏感信息,如密码)。
    • signature(签名):用自定义密钥对header和payload进行签名,确保token不被篡改——服务器接收token后,会用相同的密钥验证签名,若签名不一致则token无效。
  • 认证流程
    • 1. 客户端提交用户名/密码,服务器验证通过后,生成jwt token并返回给客户端。
    • 2. 客户端接收token后,存储在本地(如localstorage、cookie),后续所有请求都在请求头中携带token。
    • 3. 服务器拦截所有需要认证的请求,解析请求头中的token,验证token有效性(签名是否正确、是否过期)。
    • 4. token验证通过后,解析出payload中的用户标识(如用户id),根据标识查询登录人信息,返回给客户端。
  • 核心优势:无状态(服务器无需存储会话信息,减轻服务器压力)、支持跨域、可分布式部署、轻量级(token字符串体积小,传输效率高)。

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

实现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中,避免硬编码,便于后续修改和部署,参数说明如下:

  • secret:密钥,必须至少32位(jjwt的hs256算法要求密钥长度不低于256位,即32个字符),可自定义(如字母+数字组合),核心作用是签名token,必须保密,不可泄露。
  • expiration:token过期时间,单位为秒(本文配置7200秒,即2小时,可根据业务需求调整,如后台管理系统可设置1小时,app可设置7天)。
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;
        }
    }
}

关键细节与避坑点

  • 密钥生成:必须使用keys.hmacshakeyfor(secret.getbytes())生成key,不可手动构建,否则会导致签名验证失败。
  • payload存储:仅存储非敏感信息(如用户id、用户名),绝对不能存储密码、手机号等敏感数据(因为payload是base64编码,可直接解码查看)。
  • 异常捕获:validatetoken方法中捕获jwtexception(token相关异常)和illegalargumentexception(参数异常),避免因token无效导致程序崩溃。
  • 方法命名:getusernamefromtoken方法名可根据实际存储的信息修改(如getuseridfromtoken),本文因代码中存储的是用户id,实际功能是获取用户id。

模块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("用户名或密码错误");
        }
    }
}

核心注意点与优化建议

  • 密码验证:实际项目中,数据库存储的密码必须加密(如使用bcrypt加密),客户端传递的密码需先加密,再与数据库中的加密密码比对,避免明文密码传输和存储(本文代码为简化演示,未做加密处理,实际需补充)。
  • 用户校验:users.size() == 1 是简化校验,实际项目中可优化为“查询到唯一用户且密码匹配”,避免因数据库数据异常(如重复用户)导致的问题。
  • 响应格式:使用自定义result实体类统一响应格式(包含状态码、提示信息、数据),便于前端统一解析(如成功返回code=200,失败返回code=500)。

模块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");  
    }
}

拦截器核心逻辑说明

  • token获取:前端需将token放在请求头的authorization字段中,格式为“bearer 生成的token”(如bearer eyjhbgcioijiuzi1nij9...),拦截器截取前缀后获取真实token。
  • 拦截范围:拦截所有请求(/**),排除登录接口(/login)——登录接口是获取token的入口,无需认证即可访问。
  • 权限控制:token无效或未携带时,返回401未授权,阻止访问接口;token有效则放行,并将用户id存入request,供接口查询使用。

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

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

  • 客户端提交用户名/密码,发送post请求到/login接口。
  • 服务器验证用户名/密码正确,调用jwtutil.generatetoken()生成token(payload中存储用户id),返回token给客户端。
  • 客户端存储token(如localstorage),后续访问/info接口时,在请求头中携带token(authorization: bearer token)。
  • 服务器拦截器拦截/info请求,获取请求头中的token,调用jwtutil.validatetoken()验证token有效性。
  • token有效,调用jwtutil.getusernamefromtoken()解析出用户id,存入request属性中。
  • /info接口从request中获取用户id,查询数据库得到登录人信息,返回给客户端。

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

  • 环境准备:启动springboot项目,确保数据库连接正常(administratorservice能正常查询用户),拦截器已注册生效。
  • 登录测试:使用postman发送post请求(http://localhost:8080/login),请求体为json格式({"username":"admin","password":"123456"}),成功返回token。
  • 信息查询测试:发送get请求(http://localhost:8080/info),在请求头中添加authorization字段,值为“bearer 上一步返回的token”,成功返回登录人的管理员信息。
  • 无效token测试:修改token中的任意字符,再次发送/info请求,服务器返回401未授权,验证拦截器生效。

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

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

5.1 核心优化点

  • 密码加密:数据库存储的密码必须使用bcrypt等不可逆加密算法加密,客户端传递的密码需先加密再与数据库比对,避免明文传输和存储。
  • 密钥安全:生产环境中,jwt密钥(secret)不能硬编码在配置文件中,建议通过环境变量、配置中心(如nacos)注入,避免密钥泄露。
  • token过期处理:前端需监听token过期时间,在token过期前自动刷新token(如调用刷新token接口),避免用户频繁登录;服务器可设置token刷新机制(如 refreshtoken)。
  • 日志优化:在拦截器、jwtutil、接口中添加日志(如slf4j+logback),记录token生成、验证、解析的关键信息,便于问题排查(如token无效原因、登录失败原因)。
  • 接口权限细化:拦截器可根据用户角色(如管理员、普通用户)进行权限控制,不同角色可访问的接口不同,而非仅验证token有效性。

5.2 常见坑点与解决方案

  • 坑点1:token验证失败,提示签名错误——解决方案:检查生成token和验证token时使用的密钥是否一致,确保secret长度≥32位,避免密钥拼写错误。
  • 坑点2:token解析时抛出jwtexception(过期)——解决方案:检查token过期时间配置,前端及时刷新token,服务器返回401后,前端引导用户重新登录。
  • 坑点3:拦截器未生效,无需token即可访问接口——解决方案:检查拦截器是否添加@component注解(交给spring管理),是否在webmvcconfig中注册,拦截路径和排除路径是否配置正确。
  • 坑点4:前端携带token后,服务器仍返回401——解决方案:检查请求头中token的格式是否正确(是否添加bearer前缀),token是否被篡改,拦截器中token截取逻辑是否正确。
  • 坑点5:payload中存储敏感信息导致泄露——解决方案:仅存储非敏感信息(用户id、用户名),密码、手机号等敏感信息绝对不能存入payload。

六、总结与扩展

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

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

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

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

扩展方向:

  • token刷新机制:实现refreshtoken接口,用户登录后返回accesstoken(短期有效)和refreshtoken(长期有效),accesstoken过期后,用refreshtoken刷新获取新的accesstoken。
  • 多端适配:支持pc端、app端、小程序端统一认证,通过token中的设备信息,实现多端登录管理(如同一账号最多允许3台设备登录)。
  • 权限细化:结合spring security,实现基于角色的权限控制(rbac),不同角色访问不同接口,提升系统安全性。
  • token黑名单:实现token注销功能(如用户退出登录),将注销的token加入黑名单,即使token未过期,也不允许访问接口。

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

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

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com