当前位置: 代码网 > it编程>数据库>Redis > 使用Redis实现JWT令牌主动失效机制

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

2024年08月12日 Redis 我要评论
一.实现思路:登录成功后,给浏览器响应令牌的同时,把该令牌存储到redis中logininterceptor拦截器中,需要验证浏览器携带的令牌,并同时需要获取到redis中的存储的与之相同的令牌,如果

一.实现思路:

  • 登录成功后,给浏览器响应令牌的同时,把该令牌存储到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主动失效机制内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com