主页 > 手机  > 

Redis实现登录优化

Redis实现登录优化
总说

过程参考黑马程序员SpringBoot3+Vue3全套视频教程,springboot+vue企业级全栈开发从基础、实战到面试一套通关_哔哩哔哩_bilibili

目录

总说

一、Redis功能测试

1.1 添加依赖

1.2 配置

1.3 调用API测试功能

二、令牌主动失效功能

2.1 Controller层

2.2 拦截器

2.3 Controller层

2.4 测试


之前的登录逻辑,如果在修改密码后,我们会得到新的令牌,但是没有删除旧的令牌,导致用旧的令牌依然能够登录访问,所以我们在更新密码后应该要删除旧的令牌。

在用户登录成功时,我们同时向 浏览器 和 Redis 发送令牌,当浏览器携带令牌访问其他资源时,在拦截器中,我们不仅要对令牌的合法性进行校验,还要和Redis的令牌比较,二者的令牌一模一样才能通过。

我们用Redis实现旧令牌的主动失效。在用户修改密码后,我们在Redis删除令牌就能实现。

一、Redis功能测试

1.1 添加依赖

来到pom.xml中,添加Redis依赖

<!-- redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>3.4.2</version> </dependency>

1.2 配置

来到application.yml中,添加配置如下:

1.3 调用API测试功能

在test目录下创建一个RedisTest测试对象

写入代码如下:

可能会有爆红,先不管他,项目能跑

@SpringBootTest //如果在测试类上添加这个注解,在单元测试方法执行之前,会先初始化Spring容器 public class RedisTest { @Autowired private StringRedisTemplate stringRedisTemplate; //这里爆红 //测试存储 @Test public void testSet(){ //往redis中存储一个键值对 StringRedisTemplate //接受一个返回值 ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); //实现数据存储 operations.set("username","ZhangSan"); } }

没有redis,要先去安装redis

下完redis后,点击redis-server.exe启动redis

然后我们去启动测试类:

左边绿色,表示运行成功

然后我们再去redis,看看我们的键值对是否成功存入

打开redis-cil.exe

然后输入

get username

发现我们可以得到刚刚传入的键值对

我们再测试一下获取功能

完整代码如下:

@SpringBootTest //如果在测试类上添加这个注解,在单元测试方法执行之前,会先初始化Spring容器 public class RedisTest { @Autowired private StringRedisTemplate stringRedisTemplate; //这里爆红 //测试存储 @Test public void testSet(){ //往redis中存储一个键值对 StringRedisTemplate //接受一个返回值 ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); //实现数据存储 operations.set("username","ZhangSan"); } //测试存储 @Test public void testGet(){ //往redis中获取一个键值对 ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); //实现数据读取 输入到控制台 System.out.println(operations.get("username")); } }

然后测试一下:

成功得到

二、令牌主动失效功能

2.1 Controller层

来到UserController,添加对象

@Resource private StringRedisTemplate stringRedisTemplate;

修改login方法,将token存到redis中,修改完如下:

//登录方法 ,返回值token是一个字符串 @PostMapping("/login") public Result<String> login(@Pattern(regexp = "^\\S{5,16}$") String username, @Pattern(regexp = "^\\S{5,16}$")String password) { //1、根据用户名查询用户 User user = userService.findByUserName(username);//返回一个查找到的User对象 //2、判断用户是否存在 if (user == null) { //没找到 return Result.error("用户名不存在"); } //3、判断密码是否正确 user对象中是加密过的密码 if (Md5Util.getMD5String(password).equals(user.getPassword())) { //密码正确 登录成功 //创建一个map,用于记录传入token的数据集合 Map<String, Object> claims = new HashMap<>(); claims.put("id", user.getId()); //传入id和用户名 claims.put("username", user.getUsername()); //生成token String token = JwtUtil.genToken(claims); //传入数据 并生成token //把token存储到redis中 ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); operations.set(token, token, 1, TimeUnit.HOURS);// 过期时间与token过期时间一致 return Result.success(token); } return Result.error("密码错误"); }

2.2 拦截器

来到拦截器

添加代码:

完整代码:

//@Component用于标识一个类是一个 Spring 管理的组件 @Component public class LoginInterceptor implements HandlerInterceptor { @Resource private StringRedisTemplate stringRedisTemplate; //preHandle方法会在请求处理之前被调用,可以在这里进行一些前置处理,比如登录验证 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //令牌验证 String token = request.getHeader("Authorization"); //验证token try { //从redis中获取相同的token ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); String redisToken = operations.get(token); if(redisToken == null) { //token已经失效 throw new Exception(); // 抛出异常 } Map<String, Object> claims = JwtUtil.parseToken(token); //解析token 解析后的内容是一个map //可以把业务数据存储到ThreadLocal中 ThreadLocalUtil.set(claims); return true; //如果解析成功,代表登录过了,放行 } catch (Exception e) { //如果解析失败,代表没有登录,拦截 response.setStatus(401); return false; //拦截 } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //在请求处理完成之后被调用,可以在这里进行一些后置处理,比如清理ThreadLocal中的数据 ThreadLocalUtil.remove(); } }

2.3 Controller层

再次回到UserController,来到updatePwd方法

在用户更新完密码后,删除redis中对应的token

在return前面添加一句:

operations.getOperations().delete(token); // 删除token

updatePwd方法完整代码如下:

//更新密码 @PatchMapping("/updatePwd") public Result updatePwd(@RequestBody Map<String, String> params,@RequestHeader("Authorization") String token){ //1、校验参数 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("缺少必要参数"); } //2、检验密码是否正确 Map<String, Object> map = ThreadLocalUtil.get(); String username = (String) map.get("username");// 在线程中获取用户名username User user = userService.findByUserName(username); //根据用户名查询用户 if(!user.getPassword().equals(Md5Util.getMD5String(oldPwd))) { return Result.error("原密码不正确"); } //2次填写密码是否一致 if(!rePwd.equals(newPwd)) { return Result.error("两次密码不一致"); } //3、调用service完成密码更新 userService.updatePwd(newPwd); //删除redis中对应的token ValueOperations<String, String> operations = stringRedisTemplate.opsForValue(); operations.getOperations().delete(token); // 删除token return Result.success(); }

2.4 测试

先启动redis和项目

来到更新用户密码接口,更新一下用户密码

修改成功之后,我们重新去登录接口

发现我们用更新后的密码可以登录成功,更新前的密码不能登录

而且在不更换token的情况下,我们不再能访问其他接口。

功能实现完成。上传git保存一下

标签:

Redis实现登录优化由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Redis实现登录优化