欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > 令牌主动失效机制范例(利用redis)注释分析

令牌主动失效机制范例(利用redis)注释分析

2024/10/26 2:31:55 来源:https://blog.csdn.net/qq_55018264/article/details/142715844  浏览:    关键词:令牌主动失效机制范例(利用redis)注释分析

介绍该机制

  1. 令牌生成
    在需要限流的场景中,系统会根据一定的速率生成令牌,存储在 Redis 中。可以设定每秒生成的令牌数量。

  2. 令牌获取
    当用户请求时,系统会从 Redis 中获取令牌。可以使用原子性操作(如 DECR)来确保令牌的正确获取和减少。

  3. 令牌失效
    令牌的主动失效可以通过设定过期时间(TTL)来实现。当生成的令牌在一定时间内未被消费,Redis 会自动删除这些令牌。也可以通过在逻辑上判断令牌的使用情况,主动将过期的令牌从队列中剔除。

  4. 监控与调整
    在实际运行中,可以通过 Redis 的发布/订阅机制或键空间通知(Keyspace Notifications)来监控令牌的状态,动态调整生成速率或失效策略。

redis令牌失效机制的代码实现案例

redis配置

pom、yml(redis配置)
在这里插入图片描述

redis的配置文件

package com.itheima.config;import org.springframework.cache.annotation.CachingConfigurerSupport; // 引入缓存支持类
import org.springframework.context.annotation.Bean; // 引入Bean注解
import org.springframework.context.annotation.Configuration; // 引入配置注解
import org.springframework.data.redis.connection.RedisConnectionFactory; // 引入Redis连接工厂
import org.springframework.data.redis.core.RedisTemplate; // 引入通用Redis模板
import org.springframework.data.redis.core.StringRedisTemplate; // 引入字符串Redis模板@Configuration // 声明这是一个配置类
public class RedisConfig extends CachingConfigurerSupport { // 继承缓存支持类// 定义一个StringRedisTemplate Bean,用于操作String类型的键值对@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {// 使用提供的连接工厂创建StringRedisTemplate实例return new StringRedisTemplate(redisConnectionFactory);}// 定义一个通用的RedisTemplate Bean,用于操作任意类型的对象@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {// 创建RedisTemplate实例RedisTemplate<String, Object> template = new RedisTemplate<>();// 设置连接工厂,以便连接到Redis服务器template.setConnectionFactory(redisConnectionFactory);// 返回配置好的RedisTemplate实例return template;}
}

用户控制器(登录)

usercontroller

    @PostMapping("/login")public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$") String password) {//根据用户名查询用户User loginUser = userService.findByUserName(username);//判断该用户是否存在if (loginUser == null) {return Result.error("用户名错误");}//判断密码是否正确  loginUser对象中的password是密文if (Md5Util.getMD5String(password).equals(loginUser.getPassword())) {//登录成功Map<String, Object> claims = new HashMap<>();  // 创建一个存储用户信息的映射claims.put("id", loginUser.getId());           // 将用户 ID 存储在 claims 中claims.put("username", loginUser.getUsername()); // 将用户名存储在 claims 中String token = JwtUtil.genToken(claims);       // 生成 JWT,包含用户的 ID 和用户名//把token存储到redis中ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.set(token,token,1, TimeUnit.HOURS);return Result.success(token);}return Result.error("密码错误");}

使用完需要删除操作(usercontroller)

        //删除redis中对应的tokenValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.getOperations().delete(token);return Result.success();

拦截器里redis的验证

logininterceptor
@Component
public class LoginInterceptor implements HandlerInterceptor {@Autowiredprivate StringRedisTemplate stringRedisTemplate; // 注入 Redis 模板,用于操作 Redis 数据库@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 令牌验证String token = request.getHeader("Authorization"); // 从请求头中获取名为 "Authorization" 的令牌// 验证 tokentry {// 从 Redis 中获取与请求中相同的 tokenValueOperations<String, String> operations = stringRedisTemplate.opsForValue();String redisToken = operations.get(token); // 查询 Redis 数据库if (redisToken == null) {// 如果 Redis 中没有该 token,说明 token 已经失效throw new RuntimeException("Token has expired"); // 抛出异常以指示 token 失效}// 解析 token,获取业务数据(例如用户信息)Map<String, Object> claims = JwtUtil.parseToken(token);// 将业务数据存储到 ThreadLocal 中,以便后续处理使用ThreadLocalUtil.set(claims);// 放行请求,继续处理return true;} catch (Exception e) {// 如果发生异常(例如 token 失效),设置 HTTP 响应状态码为 401(未授权)response.setStatus(401);// 拦截请求,不放行return false;}}
}

测试
redisTest

package com.itheima;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;import java.util.concurrent.TimeUnit;@SpringBootTest     //如果在测试类上添加了这个注解,那么将来单元测试方法执行之前,会先初始化Spring容器
public class RedisTest {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testpublic void testSet(){//往redis中存储一个键值对  StringRedisTemplateValueOperations<String, String> operations = stringRedisTemplate.opsForValue();operations.set("username","zhangsan");operations.set("id","1",15, TimeUnit.SECONDS);}@Testpublic void testGet(){//从redis中获取一个键值对ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();System.out.println(operations.get("id"));}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com