• 快速入门JWT+Redis实现Token验证


    导言 :该文最终本人实现目的为通过JWT来生成token作为用户登录或调用api等身份验证凭证,同时简单的引入了Redis作为缓存来存放Token。用最简洁的方法给第一次接触Token的朋友们快速入门并且实际运用到项目中。不纠结于理论,只聚焦于实战,如果有希望了解更多理论的朋友,可以在看本文的过程中查询其他理论性文章。

    这几天毕设项目正准备开始搞,想到之前的项目登录没有做token密码只是md5加密,再加上实习导师的建议,我就开始搞了JWT+Redis,查了诸多参考文献资料等,花了三天时间基本完成了这个功能。

    Json Web Token

    引入JWT

    
            
                io.jsonwebtoken
                jjwt
                0.9.1
            
    复制代码

    配置JWT工具类

    Token分为三个部分,头,荷载,和签名,我们需要对这几个部分分别设置,第一个方法为创建一个JsonWebToken

    第二个工具类为检查 token 是否正常,值得注意的是,除了解析后的姓名身份等等,如果时间异常(已经超过有效期)也将被 catch 异常,所以直接写在 try-catch 中即可

    //JsonWebTokenUtil
    
    public class JsonWebToken {
    
        private static longtime= 1000*60*60*24;
        private static Stringsignature= "9991morF0GgnahZ";
    
        public static String createToken(String role,String name){
            JwtBuilder jwtBuilder = Jwts.builder();
            String jwToken = jwtBuilder
                    //链式编程 添加头
                    .setHeaderParam("typ","JWT")
                    .setHeaderParam("alg","HS256")
                    //payload 载荷
                    .claim("name",name)
                    .claim("role",role)
                    //主题
                    .setSubject("admin")
                    //有效期
                    .setExpiration(new Date(System.currentTimeMillis()+time))
                    .setId(UUID.randomUUID().toString())
                    //signature签名
                    .signWith(SignatureAlgorithm.HS256,signature)
                    //拼接前面三个
                    .compact();
            return jwToken;
        }
    
        public static boolean checkToken(String token){
            if (Objects.equals(token, "") || token == null){
                return false;
            }
    
            try {
                //解析后拿到存有token信息的集合
                Jws claimsJws1 = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
            } catch (Exception e) {
                System.out.println("【Error】token解密异常");
                e.printStackTrace();
                return false;
            }
            return true;
    //        Claims claims = claimsJws1.getBody();
    //        System.out.println(claims.get("name"));
    //        System.out.println(claims.get("role"));
    //        System.out.println(claims.getId());
    
        }
    }
    复制代码

    在控制层对应URL中使用

    只展示与Token相关核心代码

    adminLogin 为登录VO内有phone password token三个字段,最后返回时将password清空保证安全(并非唯一方式也并非最佳方式此返回仅供参考)

    getOne 为本人写的获取用户信息的函数,并非本文重点内容,在此声明不做阐述。

    String name = getOne(queryWrapper).getAdminName();
    //下面为核心代码 
    //获取Token
    adminLogin.setToken(JsonWebToken.createToken("admin",name));
    //将用户token写入Redis缓存 以token为key与value前端不用多传值,后两个参数为过期时间
    stringRedisTemplate.opsForValue().set(adminLogin.getToken(),adminLogin.getToken(),1000*60*60*24*7, TimeUnit.SECONDS);
    //上面为核心代码
    adminLogin.setPassword("");
    return JsonResultUtils.successMsg("登录成功",adminLogin);
    复制代码

    完成到这一步之后,恭喜你已经完成了基础的token配置(可以配合解析token直接用了)但是,一般来说我们用户使用过程中会让有些功能需要token,有些功能不需要token,那具体那些需要哪些不需要呢?我们需要在后台做一个URL的区分,这个时候就需要用到 拦截器

    拦截器的配置

    第一步需要先写好拦截的控制方法

    在下面代码中已有对应的详细注释,只对个别点做单独说明

    Authorization 为前端设置的在请求头中放置的token值,后续会有说明前端如何设置

    @Component
    public class TokenHandler implements HandlerInterceptor {
    
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            // 注意:放行浏览器的预检请求
            System.out.println("进入预检");
            if (request.getMethod().equals("OPTIONS")) {
                return true;
            }
            // 获取请求头中携带的token值
            String token = request.getHeader("Authorization");
            // token验证
            //查看token是否为空 查看token是否合法
            if(JsonWebToken.checkToken(token)) {
                //查看Redis中有无token
                String value = stringRedisTemplate.opsForValue().get(token);
                if (Objects.equals(value, token)) {
                    System.out.println("【success】token与redis中的匹配成功");
                    return true;
                }
            }
                System.out.println("【error】 token与redis中的匹配失败");
    //            throw new Exception("【error】 token与redis中的匹配失败");
                // 验证失败,拦截请求
                return false;
        }
    
    }
    复制代码

    第二步我们需要去写好拦截的配置

    第一个方法为拦截器方法,在注释中已经讲的很明白了,如有多个排除拦截URL,用逗号分隔,或者写在List中

    第二个方法为跨域,反正你先这样配上,控制层用注解去跨域,因为根据查阅的部分资料文章说这个跨域可能会影响token,我没碰到过不清楚,反正先配上hh

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
    
        @Autowired
        private TokenHandler tokenHandler;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            //添加tokenHandler拦截器 全部拦截 排除"/admin/login"
            registry.addInterceptor(tokenHandler).addPathPatterns("/**").excludePathPatterns("/admin/login");
        }
    		
    		//跨域配置
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")  // 允许跨域请求的地址
                    .allowedOriginPatterns("*")  // 允许跨域请求的域名
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "PATH")  // 允许请求的方式
                    .allowCredentials(true)  // 是否允许证书(cookies)
                    .maxAge(3000);  // 跨域允许时间
        }
    
    }
    复制代码

    至此为止你的token就已经大功告成了!

    前端配置!

    配置axios的request方法中拦截request方法

    注意:如果你出错了,请检查你是否拿到token时把其存入了localStorage!

    Request.interceptors.request.use(config => {
        config.headers['Content-Type'] = 'application/json;charset=utf-8';
        // 在浏览器的 Session Storage 中拿到 token 值
        config.headers.Authorization =window.localStorage.getItem("token");
        return config;
    })
    复制代码

    Redis

    引入Redis启动器

    
            
                org.springframework.boot
                spring-boot-starter-data-redis
            
    复制代码

    如果出错!请想一想你装Redis没,装了开没,开了ping没,ping了pong没。

    如果一切正常但是依旧报错,请移步搜索,因为我没踩过坑…

    本文尚未设计点

    1. 前端Router路由时是否需要拦截? 解决方案:设置路由守卫,后端新开一个checktoken的api,跳转时询问后端。
    2. 相信不完美的地方,尚未考虑到的地方还有很多,请大家多多指教,将持续改进更新本文。

     

  • 相关阅读:
    Selenium自动化最佳实践技巧等你来学
    java计算机毕业设计家教信息管理系统源码+mysql数据库+系统+lw文档+部署
    AcWing第 79 场周赛
    前端ES6/7/8/9/10,CSS3,HTML5新特性总结
    阿里开源组件Nacos实战操作之安装部署完整版
    强化学习 补充笔记(TD算法、Q学习算法、SARSA算法、多步TD目标、经验回放、高估问题、对决网络、噪声网络)
    【Linux】Linux中安装Tomcat,超级详细
    mongodb基本操作及使用
    通过OptaPlanner优化 COVID-19 疫苗接种预约安排(2)
    如何学习爬虫技术(问答版)
  • 原文地址:https://blog.csdn.net/Trouvailless/article/details/126906283