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("/**");
    }
}

后记:

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

相关推荐
suaizai_2 小时前
Fastjson高危漏洞紧急修复指南
spring boot
SomeB1oody5 小时前
【RustyML入门】6.3. 并行归约
开发语言·后端·机器学习·rust·教程
正儿八经的少年6 小时前
布隆过滤器(解决redis缓存穿透步骤之一)
数据库·redis·缓存
Profile排查笔记6 小时前
指纹浏览器哪个好?从 Profile、代理、权限和自动化能力判断是否适合
前端·人工智能·后端·自动化
用户938515635076 小时前
用 AI 结对编程从 0 搭一个"单词后台管理系统":Next.js + Supabase + Drizzle + shadcn/ui 全记录
后端·postgresql·next.js
爱学习的小邓同学7 小时前
Golang --- (1)第一个Golang程序
开发语言·后端·golang
小灰灰搞电子8 小时前
Rust+Slint 实现的“DNA双螺旋”加载动画源码分享
后端·rust·slint·加载动画
面向Google编程8 小时前
向量库不再囤数据:Milvus 3.0 零拷贝直读数据湖
后端
gugucoding9 小时前
59. 【Java】Spring Boot 入门:第一个 Web 应用
java·开发语言·spring boot
IT_陈寒9 小时前
Redis内存警告竟是因为这个不起眼的配置项
前端·人工智能·后端