使用Redis实现JWT令牌主动失效机制

 更新时间:2024年08月12日 10:47:05   作者:记得开心一点嘛  
JWT是一种轻量级的身份验证和授权机制,它是一种 JSON 格式的数据串,通常用于客户端和服务端之间的单点登录(Single Sign-On, SSO)场景,本文给大家介绍了如何使用Redis来实现JWT令牌主动失效机制,需要的朋友可以参考下

一.实现思路:

  • 登录成功后,给浏览器响应令牌的同时,把该令牌存储到Redis中
  • LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到Redis中的存储的与之相同的令牌,如果获取到证明令牌有效,如果没有获取到则令牌无效
  • 当用户修改密码成功后,删除Redis中存储的旧令牌

二.实现代码解析:

1.首先配置Redis的相关配置文件:

(1)pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2)在application.yml中配置相关信息:

spring:
  data:
    redis:
      host: localhost
      port: 6379
      password: *******  #Redis的密码
      database: ***      #指定使用哪个数据源(可不写,但默认是DB0)

(3)编写配置类,创建RedisTemplate对象:

我们使用RedisTemplate这个类对象内封装的方法来操作Redis,所以我们在配置类内创建RedisTemplate并用Bean注解将其交给Spring容器管理。

@Configuration
@Slf4j
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        log.info("开始创建Redis模板对象...0");
        RedisTemplate redisTemplate = new RedisTemplate();
        //设置redis的连接工厂对象
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置redis key的序列化器,这里反应的是Redis图形化工具上value值的不同
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

2.登录成功后,给浏览器响应令牌的同时,把该令牌存储到Redis中:

@RestController
@RequestMapping("/user")
@Validated
public class UserController {
 
    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate redisTemplate;
 
    /**
     * 用户登录
     * @param username
     * @param password
     * @return
     */
    @PostMapping("/login")
    public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username ,@Pattern(regexp = "^\\S{5,16}$") String password){
        //根据username查询用户
        User loginUser = userService.findByUserName(username);
        //判断是否存在
        if(loginUser == null){
            return Result.error("用户名错误");
        }
        //判断密码是否正确
        if(Md5Util.getMD5String(password).equals(loginUser.getPassword())){
            //登录成功,创建JWT令牌
            Map<String,Object> claims = new HashMap<>();
            claims.put("id",loginUser.getId());
            claims.put("username",loginUser.getUsername());
            String token = JwtUtil.genToken(claims);
            //将token存储到redis中
            redisTemplate.opsForValue().set(token,token,1, TimeUnit.HOURS);//key,value,时间值,时间单位
            return Result.success(token);
        }
        return Result.error("密码错误");
    }
}

3.LoginInterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到Redis中的存储的与之相同的令牌:

package com.itheima.bigdealboot.interceptors;
 
 
import com.itheima.bigdealboot.utils.JwtUtil;
import com.itheima.bigdealboot.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
 
import java.util.Map;
//拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @Override
    public boolean preHandle(HttpServletRequest request , HttpServletResponse response , Object handle) throws Exception{
        String token = request.getHeader("Authorization"); //Authorization为请求头的名字
        try {
            //从Redis中国获取相同的token
            String redisToken = (String) redisTemplate.opsForValue().get(token);
            if(redisToken == null){
                //token已经失效,抛出异常
                throw new RuntimeException();
            }
            //令牌验证
            Map<String,Object> claims = JwtUtil.parseToken(token);
            //线程开辟空间存储
            ThreadLocalUtil.set(claims);
            //放行
            return true;
        }catch (Exception e){
            //http响应状态码为401在·
            response.setStatus(401);
            //不放行
            return false;
        }
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //清空线程数据
        ThreadLocalUtil.remove();
    }
}

4.当用户修改密码成功后,删除Redis中存储的旧令牌:

@RestController
@RequestMapping("/user")
@Validated
public class UserController {
 
    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate redisTemplate;
 
    @PatchMapping("/updatePwd")
    public Result updatePwd(@RequestBody Map<String,String> params,@RequestHeader("Authorization") String token){
        //校验参数
        String oldPwd = params.get("old_pwd");
        String newPwd = params.get("new_pwd");
        String rePwd = params.get("re_pwd");
        if(StringUtils.hasLength(oldPwd) || StringUtils.hasLength(newPwd) || StringUtils.hasLength(rePwd)){
            return Result.error("缺少必要参数");
        }
        //校验
        Map<String,Object> map = ThreadLocalUtil.get();
        String username = (String) map.get("username");
        User loginUser = userService.findByUserName(username);
        if(!loginUser.getPassword().equals(Md5Util.getMD5String(oldPwd))){
            return Result.error("原密码填写不正确");
        }
        if(!rePwd.equals(newPwd)){
            return Result.error("两次填写的新密码不一样");
        }
        //更新密码
        userService.updatePwd(newPwd);
        //删除redis中对应的token
        redisTemplate.opsForValue().getOperations().delete(token);
        return Result.success();
    }
}

到此这篇关于使用Redis实现JWT令牌主动失效机制的文章就介绍到这了,更多相关Redis JWT主动失效机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Redis用链表实现消息队列

    详解Redis用链表实现消息队列

    Redis有两种方式实现消息队列,一种是用Redis自带的链表数据结构,另一种是用Redis发布/订阅模式实现,这篇文章先介绍链表实现消息队列,有需要的朋友们可以参考借鉴。
    2016-09-09
  • Redis数据一致性详解

    Redis数据一致性详解

    文章主要讨论了分布式系统中的数据一致性模型、缓存使用场景以及数据同步策略,一致性模型包括强一致性、弱一致性和最终一致性,缓存使用场景主要在高并发读取数据时提升性能,数据同步策略分为先删除缓存再更新数据库和先更新数据库再删除缓存两种
    2024-11-11
  • 浅谈Redis缓存更新策略

    浅谈Redis缓存更新策略

    这篇文章主要介绍了Redis缓存更新策略的相关资料,讲解的十分细致,有需要的小伙伴可以参考下
    2022-08-08
  • Redis数据库的数据倾斜详解

    Redis数据库的数据倾斜详解

    Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,需要的朋友可以参考下
    2023-07-07
  • redis简介_动力节点Java学院整理

    redis简介_动力节点Java学院整理

    这篇文章主要介绍了redis简介,Redis是一个开源的,先进的 key-value 存储可用于构建高性能,可扩展的 Web 应用程序的解决方案,有兴趣的可以了解一下
    2017-08-08
  • Redis底层类型之json命令使用

    Redis底层类型之json命令使用

    这篇文章主要为大家介绍了Redis底层类型之json命令使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 如何高效使用Redis作为LRU缓存

    如何高效使用Redis作为LRU缓存

    这篇文章主要介绍了如何高效使用Redis作为LRU缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Redis高可用部署架构的实现

    Redis高可用部署架构的实现

    本文主要介绍了Redis高可用部署架构的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • Redis配置文件redis.conf详细配置说明

    Redis配置文件redis.conf详细配置说明

    本文列出了Redis的配置文件redis.conf的各配置项的详细说明,简单易懂
    2018-03-03
  • 基于Redis分布式BitMap的应用分析

    基于Redis分布式BitMap的应用分析

    这篇文章主要介绍了基于Redis分布式BitMap的应用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03

最新评论