Springboot3+Vue3实现 jwt 登录鉴权

为什么要做鉴权?

因为管理系统的数据是敏感的,隐私的,而且一般每个角色权限是不同的,所以必须在数据的增删改查操作的时候对访问用户做权限验证。

什么是 JWT?

JWT(JSON Web Token)是一种用于在网络应用中安全地传输信息的开放标准(RFC 7519)。它以紧凑且自包含的方式,通过 JSON 对象在各方之间传递经过验证的信息。

JWT由三部分组成,用 . 分割:
Header(头部):包含算法(如 HMAC SHA256 或RSA)和令牌类型(固定为JWT)。

{
   "alg": "HS256",
   "typ": "JWT"
}

Payload(负载):携带声明(如用户身份、权限、有效期等),分为三类:
-Registered claims(预定义字段,如 exp 过期时间、 iss 签发者)
-Public claims(公开自定义字段,需避免冲突)
-Private claims(私有字段,双方协商)

{
   "sub":"1234567890",
   "name":"John Doe",
   "admin":true
}

Signature(签名):对头部和负载的签名,防止数据篡改

集成 JWT

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

生成 Token

package com.example.utils;

import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import java.util.Date;

public class TokenUtils {
    /**
     * 生成 Token
     */
    public static String createToken(String data,String sign) {
        return JWT.create().withAudience(data) //将 userId-role 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetDay(new Date(), 1)) //1天后 token 过期
                .sign(Algorithm.HMAC256(sign));//以 password 作为 token 的密钥,HMAC256算法加密

    }
}

在登陆接口返回 Token

AdminService 的 login 方法

//创建 token 并返回给前端
       String token = TokenUtils.createToken(dbAdmin.getId() + "-" + "ADMIN",dbAdmin.getPassword());
        dbAdmin.setToken(token);
        return dbAdmin;
    }

Token 的格式

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI2LUFETUlOIiwiZXhwIjoxNzcxNzMyNjI4fQ.QckQYkwd45YBfz9sFKdr9A2Ca6nJ2t0HGpRyEdKVoto

屏幕截图 2026-02-21 115930

JWT 拦截器

WebConfig

package com.example.common;

import org.springframework.context.annotation.Bean;
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(jwtInterceptor())
               .addPathPatterns("/**")
               .excludePathPatterns("/login","/register");
    }

    @Bean
    public JWTInterceptor jwtInterceptor() {
        return new JWTInterceptor();
    }
}
package com.example.common;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.entity.Account;
import com.example.entity.Admin;
import com.example.exception.CustomerException;
import com.example.service.AdminService;
import com.example.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class JWTInterceptor implements HandlerInterceptor {

    @Resource
    AdminService adminService;
    @Resource
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.从 http 请求的 header 中获取 token
        String token = request.getHeader("token");
        if (StrUtil.isEmpty(token)) {
            //如果没拿到,从参数里再拿一次
            token = request.getParameter("token");
        }
        //2.开始执行认证
        if(StrUtil.isBlank(token)){
            throw new CustomerException("401","您无权限操作");
        }

        Account account = null;
        try {
            //拿到 token 的载荷数据
            String audience = JWT.decode(token).getAudience().get(0);
            String[] split = audience.split("-");
            String userId = split[0];
            String role = split[1];
            //根据 token 解析出来的 userId 去对应的表查询用户信息
            if ("ADMIN".equals(role)) {
               account = adminService.selectById(userId);
            } else if ("USER".equals(role)) {
                account = userService.selectById(userId);
            }
        }catch (Exception e){
            throw new CustomerException("401","您无权限操作");
        }
        if (account == null) {
            throw new CustomerException("401","您无权限操作");
        }
       try {
           //验证签名
           JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(account.getPassword())).build();
           jwtVerifier.verify(token);
       }catch (Exception e){
           throw new CustomerException("401","您无权限操作");
       }
        return true;
    }
}

出现 401 错误,您无权限访问数据怎么办?

屏幕截图 2026-02-21 125645

在 vue 的 request.js 的拦截器里面加上统一的请求头 token

屏幕截图 2026-02-21 130105

屏幕截图 2026-02-21 130455

request.js 的代码示例

import axios  from "axios";
import {ElMessage} from "element-plus";
import router from "@/router/index.js";

const request = axios.create({
    baseURL:'http://localhost:9999',
    timeout:30000 //后台接口超过时间
})

//request 拦截器
//可以自请求发送前对请求做一些处理
request.interceptors.request.use(config => {
    config.headers['Content-Type'] = 'application/json;charset=utf-8';
    let user = JSON.parse(localStorage.getItem('code_user') || '{}')
    config.headers['token'] = user.token
    return config
},error => {
    return Promise.reject(error)
});

//respond 拦截器
//可以在接口响应后统一处理结果
request.interceptors.response.use(
    response => {
        let res = response.data;
        //兼容服务端返回的字符串数据
        if (typeof res == 'string'){
            res = res ? JSON.parse(res) : res
        }
        if (res.code === '401'){
            ElMessage.error(res.msg)
            router.push('/login')
        }else {
            return res;
        }
    },
    error => {
        if (error.response.status === 404){
            ElMessage.error('未找到请求接口')
        }else if (error.response.status ===500){
            ElMessage.error('系统异常,请查看后端控制台报错')
        }else {
            console.error(error.message)
        }
        return Promise.reject(error)
    }
)

export default request

解析 Token 获取用户信息

  /**
     * 获取当前登录的用户信息
     */
package com.example.utils;

import cn.hutool.core.date.DateUtil;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.entity.Account;
import com.example.service.AdminService;
import com.example.service.UserService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;

@Component
public class TokenUtils {
    @Resource
    AdminService adminService;
    @Resource
    UserService userService;

    static AdminService staticAdminService;
    static UserService staticUserService;

    //Springboot工程启动后会加载这段代码
    @PostConstruct
    public void init() {
        staticAdminService = adminService;
        staticUserService = userService;
    }

    /**
     * 生成 Token
     */
    public static String createToken(String data,String sign) {
        return JWT.create().withAudience(data) //将 userId-role 保存到 token 里面,作为载荷
                .withExpiresAt(DateUtil.offsetDay(new Date(), 1)) //1天后 token 过期
                .sign(Algorithm.HMAC256(sign));//以 password 作为 token 的密钥,HMAC256算法加密

    }
    /**
     * 获取当前登录的用户信息
     */
    public static Account getCurrentUser() {
        Account account = null;
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        if(StrUtil.isBlank(token)){
            token = request.getParameter("token");
        }
        //拿到 token 的载荷数据
        String audience = JWT.decode(token).getAudience().get(0);
        String[] split = audience.split("-");
        String userId = split[0];
        String role = split[1];
        //根据 token 解析出来的 userId 去对应的表查询用户信息
        if ("ADMIN".equals(role)) {
          return account = staticAdminService.selectById(userId);
        } else if ("USER".equals(role)) {
            return account = staticUserService.selectById(userId);
        }
        return null;
    }
}

在 service 方法里面获取当前的登录用户信息

  Account currentUser = TokenUtils.getCurrentUser();
posted @ 2026-02-22 16:10  坚持努力学习ing  阅读(1)  评论(0)    收藏  举报