SpringBoot项目集成Redis+JWT实现系统登录token校验

原理

  1. 用户登录系统时,后端拿到账号密码进行登录校验(查询数据库),校验通过生成token返回给前端,并放行请求的资源
  2. 后续前端每次请求后端接口时,都在请求头中带上token,后端的全局拦截器拦截到请求,去redis查询缓存的token,找到对应token则放行请求到对应接口方法,否则返回未登录提醒。

pom文件中引入依赖(gradle同样)

xml 复制代码
<!-- Redis 相关依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- JWT 相关依赖 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.2</version>
</dependency>

配置redis

xml 复制代码
# Redis 连接配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=your_redis_password

JWT Token 生成校验工具

java 复制代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component
public class JwtTokenUtil {

    private static final String SECRET_KEY = "your_secret_key";
    private static final long EXPIRATION_TIME = 86400000; // 10 days

    public String generateToken(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET_KEY)
                .compact();
    }

    public String getUsernameFromToken(String token) {
        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody().getSubject();
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

用户登录控制器:

java 复制代码
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.RestController;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.HashMap;
import java.util.Map;

@RestController
public class LoginController {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/login")
    public Map<String, String> login(@RequestBody Map<String, String> request) {
        String username = request.get("username");
        String password = request.get("password");

        // todo 这里可以加入登录逻辑,验证用户名密码
        // 校验通过 生成 Token
        // 校验不通过 给出错误提示用户名密码错误
        String token = jwtTokenUtil.generateToken(username);

        // 缓存 Token 到 Redis
        redisTemplate.opsForValue().set(username, token);
        // 设置过期时间
        redisTemplate.expire(username, jwtTokenUtil.EXPIRATION_TIME, TimeUnit.MILLISECONDS);
		//token返回给前端
        Map<String, String> response = new HashMap<>();
        response.put("token", token);
        return response;
    }
}

编写全局拦截器

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtTokenInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
	
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 排除swagger访问接口
        String path = request.getRequestURI();
        if (path.contains("swagger") || path.contains("api-docs")) {
            return true;
        }

        String token = request.getHeader("Authorization");
		
        // 校验 Token
        if (token == null || !jwtTokenUtil.validateToken(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("Please login first.");
            return false;
        }
		//todo 查询redis缓存的token进行比对,比对上放行请求
        return true;
    }
}

注册拦截器:

java 复制代码
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 WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JwtTokenInterceptor()).addPathPatterns("/**");
    }
}

后记:

以上实现过程因项目不同会有所调整,这里只是提供一种能够实现的方案。

相关推荐
点燃大海29 分钟前
SpringAI构建智能体
java·spring boot·spring·springai智能体
xier_ran31 分钟前
【infra之路】02_RadixAttention与KV_Cache管理
java·spring boot·spring
Steadfast_GG31 分钟前
Redis中的通用命令
redis·缓存
swipe38 分钟前
做多轮对话 Agent,为什么我建议把短期记忆放到 Redis
后端·面试·llm
小二·38 分钟前
Redis 内存溢出(OOM)排查与恢复实战
数据库·redis·bootstrap
pqk6V6Vep39 分钟前
Redis 分布式锁进阶第一篇讲解
数据库·redis·分布式
码客日记1 小时前
Spring Boot 配置文件敏感信息加密(Jasypt 企业级完整方案)
java·spring boot·git
giaz14n9X1 小时前
Redis 分布式锁进阶第六十一篇
数据库·redis·分布式
程序员黑豆1 小时前
AI全栈开发之Java:什么是JDK
前端·后端·ai编程
阿明在折腾1 小时前
从Canvas到AI模型:我在线工具站里的图片处理实战
前端·后端