您现在的位置是:首页 >技术教程 >springboot使用shiro验证登录并用JWT生成token,并支持验证token刷新,token里存放用户名、部门、用户id、部门id,放在拦截器里面,封装成java工具类网站首页技术教程

springboot使用shiro验证登录并用JWT生成token,并支持验证token刷新,token里存放用户名、部门、用户id、部门id,放在拦截器里面,封装成java工具类

木易--杨 2026-07-04 12:01:04
简介springboot使用shiro验证登录并用JWT生成token,并支持验证token刷新,token里存放用户名、部门、用户id、部门id,放在拦截器里面,封装成java工具类

JWT 工具类 (JwtUtils.java)

import io.jsonwebtoken.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtils {
    // JWT 密钥
    private static final String SECRET_KEY = "your-secret-key";
    // JWT 过期时间(单位:毫秒)
    private static final long EXPIRATION_TIME = 86400000; // 24 小时
    // Token 刷新时间(单位:毫秒)
    private static final long REFRESH_TIME = 3600000; // 1 小时

    // 生成 Token(包含用户名、部门、用户ID、部门ID)
    public static String generateToken(String username, String dept, String userId, String deptId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("dept", dept);
        claims.put("userId", userId);
        claims.put("deptId", deptId);

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_MS))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // 解析 Token
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }

    // 验证 Token 有效性
    public static boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (ExpiredJwtException | SignatureException | MalformedJwtException e) {
            return false;
        }
    }
	/**
     * 刷新 Token
     *
     * @param token 旧的 Token
     * @return 新的 Token
     */
    public static String refreshToken(String token) {
        String username = getUsernameFromToken(token);
        return generateToken(username);
    }
}

拦截器:JwtInterceptor

在拦截器中验证 JWT Token 的有效性,并支持 Token 刷新。

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
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 {
        // 从请求头中获取 Token
        String token = request.getHeader("Authorization");

        // 如果 Token 不存在,返回未授权错误
        if (token == null || token.isEmpty()) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: Token is missing");
            return false;
        }

        // 验证 Token 是否有效
        if (!JwtUtils.validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Unauthorized: Invalid token");
            return false;
        }

        // 检查 Token 是否需要刷新
        if (JwtUtils.isTokenNeedRefresh(token)) {
            // 生成新的 Token
            String newToken = JwtUtils.refreshToken(token);
            // 将新的 Token 添加到响应头中
            response.setHeader("Authorization", newToken);
        }

        // 将用户名设置到 Shiro 的 Subject 中
        String username = JwtUtils.getUsernameFromToken(token);
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()) {
            currentUser.login(new JwtToken(token));
        }

        // 如果 Token 有效,继续执行请求
        return true;
    }
}

自定义 Token:JwtToken

实现 Shiro 的 AuthenticationToken 接口,用于封装 JWT Token。

import org.apache.shiro.authc.AuthenticationToken;

public class JwtToken implements AuthenticationToken {

    private final String token;

    public JwtToken(String token) {
        this.token = token;
    }

    @Override
    public Object getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
        return token;
    }
}

配置拦截器

在 Spring Boot 中配置拦截器。

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"); // 排除登录路径
    }
}

登录接口

在控制器中实现登录接口,生成 JWT Token 并返回给客户端。

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        // 使用 Shiro 进行登录验证
        if (ShiroUtils.login(username, password)) {
            // 生成 JWT Token
            String token = JwtUtils.generateToken(username);
            return "Login successful! Token: " + token;
        } else {
            return "Login failed!";
        }
    }
}

Shiro 工具类:ShiroUtils

封装 Shiro 的常用操作。

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;

public class ShiroUtils {

    /**
     * 用户登录验证
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录成功返回 true,否则返回 false
     */
    public static boolean login(String username, String password) {
        Subject currentUser = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            // 执行登录
            currentUser.login(token);
            return true;
        } catch (AuthenticationException e) {
            // 登录失败
            return false;
        }
    }
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。