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


    原理

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

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

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
    
    <dependency>
        <groupId>io.jsonwebtokengroupId>
        <artifactId>jjwtartifactId>
        <version>0.11.2version>
    dependency>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    配置redis

    # Redis 连接配置
    spring.redis.host=localhost
    spring.redis.port=6379
    spring.redis.password=your_redis_password
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    JWT Token 生成校验工具

    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;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    用户登录控制器:

    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;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    编写全局拦截器

    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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    注册拦截器:

    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("/**");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

  • 相关阅读:
    记录一次官网访问很慢的情况
    EfficientFormer:高效低延迟的Vision Transformers
    vscode插件开发(三)命令
    Wireshark下载、Wireshark使用、Wireshark抓包、ARP抓包、ICMP抓包、TCP抓包、HTTP抓包
    css3 初步了解
    【趣学Python算法100例】兔子产子
    主流音视频芯片交叉编译工具链版本
    C语言——指针进阶
    ReentrantLock 先删再批量保存 ReentrantLock有啥用
    kotlin retrofit
  • 原文地址:https://blog.csdn.net/Jactil/article/details/136546387