ruoyi-vue版本(三十)Spring Security 安全框架中token的生成与解析

news2024/12/28 18:53:49

目录

  • 1 使用
  • 2 写工具类
  • 3 使用工具类

1 使用

1 项目里面添加依赖

   <!-- Token生成与解析-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

在这里插入图片描述

2 写工具类

package com.ruoyi.framework.web.service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import eu.bitwalker.useragentutils.UserAgent;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * token验证处理
 * 当前类作为bean 对象,让其他类调用  进行使用
 *
 * 对令牌  进行操作
 * @author jing
 * 已录
 */
@Component
public class TokenService
{
    // 令牌自定义标识  Authorization
    @Value("${token.header}")
    private String header;

    // 令牌秘钥  abcdefghijklmnopqrstuvwxyz
    @Value("${token.secret}")
    private String secret;

    // 令牌有效期(默认30分钟)
    @Value("${token.expireTime}")
    private int expireTime;

    // 秒
    protected static final long MILLIS_SECOND = 1000;
    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;

    // redis  工具类
    @Autowired
    private RedisCache redisCache;

    /**
     * 根据前端传过来的  token  获取用户身份信息
     * 根据request  获取到用户的信息
     *
     * 也就是解析  token,获取用户信息
     * @return 用户信息
     */
    public LoginUser getLoginUser(HttpServletRequest request)
    {
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StringUtils.isNotEmpty(token))
        {
            try
            {
                // 解析token
                Claims claims = parseToken(token);
                // 解析对应的权限以及用户信息   返回给用户的是uuid
                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
                //  redis里面缓存的key,  根据uuid  拼接返回  redis 所存放的key
                String userKey = getTokenKey(uuid);
                // 根据key  从redis  里面 获取用户的具体信息
                LoginUser user = redisCache.getCacheObject(userKey);
                return user;
            }
            catch (Exception e)
            {
            }
        }
        return null;
    }

    /**
     * 获取请求token
     *  根据request  获取到前端传过来的 token
     * @param request
     * @return token
     */
    private String getToken(HttpServletRequest request)
    {
        //          # 令牌自定义标识
        //    header: Authorization
        //        从request   里面获取到Authorization变量的值
        String token = request.getHeader(header);// 获取到token的具体值
        //      令牌前缀    TOKEN_PREFIX = "Bearer "
        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
        {
            token = token.replace(Constants.TOKEN_PREFIX, "");
        }
        return token;
    }


    /**
     * 从令牌中获取数据声明
     *将前端传过来的token  作为参数 ,传入
     * @param token 令牌
     * @return 数据声明
     */
    private Claims parseToken(String token)
    {
        //        使用第三方的 工具  解析token ,获取到 具体数据
        return Jwts.parser()
                //                密钥
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    /**
     * 获取请求token   的key
     * 就是在redis里面  存的  key
     *  LOGIN_TOKEN_KEY = "login_tokens:"
     */
    private String getTokenKey(String uuid)
    {
        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
    }





    /**
     * 设置用户身份信息
     * 将用户信息存储到reids 里面
     */
    public void setLoginUser(LoginUser loginUser)
    {
        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
        {
            //  往redis 里面设置
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新令牌有效期
     *
     * @param loginUser 登录信息
     */
    public void refreshToken(LoginUser loginUser)
    {
        //  登录时间
        loginUser.setLoginTime(System.currentTimeMillis());
        // 设置  过期时间
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
        // 根据uuid将loginUser缓存
        //  loginUser.getToken() = 用户唯一标识  uuid   就是登陆成功返回给前端的token 里面存放的是uuid
        // 具体的信息是存放在  redis里面
        String userKey = getTokenKey(loginUser.getToken());
        //        将用户的信息,保存到redis里面
        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }

    /**
     * 删除用户身份信息
     * 根据前端传过来的  token 唯一标志  uuid
     * redis  里面进行删除token
     */
    public void delLoginUser(String token)
    {
        if (StringUtils.isNotEmpty(token))
        {
        //            获取请求token   的key
        //     * 就是在redis里面  存的  key
            String userKey = getTokenKey(token);
            redisCache.deleteObject(userKey);
        }
    }

    /**
     * 创建令牌
     * 根据登录成功的用户  创建令牌
     * @param loginUser 用户信息
     * @return 令牌
     */
    public String createToken(LoginUser loginUser)
    {
        String token = IdUtils.fastUUID();// 随机的uuid
        // 返回给前端的  token 里面存放的就是 uuid
        loginUser.setToken(token);

        setUserAgent(loginUser);// 设置代理
        //        将用户的信息存储到  redis里面
        refreshToken(loginUser);// 刷新缓存

        Map<String, Object> claims = new HashMap<>();
        //       Constants.LOGIN_USER_KEY  令牌前缀 login_user_key
        claims.put(Constants.LOGIN_USER_KEY, token);
        return createToken(claims);
    }

    /**
     * 设置用户代理信息
     *
     * @param loginUser 登录信息
     */
    public void setUserAgent(LoginUser loginUser)
    {
        //        根据request 获取代理对象
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        //        根据request 获取 当前请求的  IP
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        loginUser.setIpaddr(ip);
        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));//登录地点
        loginUser.setBrowser(userAgent.getBrowser().getName());// 浏览器类型
        loginUser.setOs(userAgent.getOperatingSystem().getName());// 操作系统
    }

    /**
     * 从数据声明生成令牌
     * 使用数据声明,密钥生成token
     *
     * claims  这个里面存放的是  uuid
     * @param claims 数据声明
     * @return 令牌
     */
    private String createToken(Map<String, Object> claims)
    {
        String token = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret).compact();
        return token;
    }

    /**
     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
     *
     * @param loginUser
     * @return 令牌
     */
    public void verifyToken(LoginUser loginUser)
    {
        long expireTime = loginUser.getExpireTime();// 过期时间
        long currentTime = System.currentTimeMillis();// 当前时间
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
        //        如果过期时间  间隔在设置的间隔之内
        {
        //            刷新缓存
            refreshToken(loginUser);
        }
    }









    /**
     * 从令牌中获取用户名
     * 将前端传过来的token  作为参数 ,传入
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token)
    {
        Claims claims = parseToken(token);
        return claims.getSubject();
    }



}

3 使用工具类

使用这个工具类 生成token 和 解析token

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/711012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MQ】消息队列的简介以及常见问题的解决方案

MQ MQ的基本概念 MQ全称Message Queue&#xff08;消息队列&#xff09;&#xff0c;实在消息的传输过程中保存消息的容器。多用于分布式系统之间的通信。 分布式系统的两种通信方式&#xff1a;直接调用、借助第三方间接完成 发送者成为生产者&#xff0c;接受者称为消费者…

想要用独立站打造跨境电商品牌吗?这些方法学起来吧!

随着互联网的发展&#xff0c;越来越多的跨境电商卖家开始考虑在独立站上打造自己的品牌。相比于在第三方平台上经营&#xff0c;拥有独立站不仅能够提高品牌认知度和形象&#xff0c;还能够更好地控制产品质量、维护顾客关系&#xff0c;以及获取更多的利润。而要打造一个成功…

CSS盒模型

目录 盒子区域包含块/containing block包含块的确定包含块的影响 行盒/line-boxes行盒的特性vertical-align BFCFCBFC的创建BFC的作用 关于BFC解决margin折叠问题关于设置overflow:auto解决浮动塌陷问题BFC解决塌陷问题的两个条件BFC计算高度规则 盒子区域 浏览器在展示每一个…

N-121基于微信小程序网上书城系统

开发工具&#xff1a;IDEA、微信小程序 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;vue、uniapp 服务端技术&#xff1a;springbootmybatisredis 本系统分微信小程序和管理后台两部分&a…

(23)目标检测算法之YOLOv6 (1)全流程指南:环境安装、模型配置、训练及推理

目标检测算法之YOLOv6 (1)全流程指南&#xff1a;环境安装、模型配置、训练及推理 本文向将介绍 YOLOv6 的整体框架&#xff0c;并提供详细的教程链接。官方论文 ☞ YOLOv6: A Single-Stage Object Detection Framework for Industrial Applicationsv3.0版本论文更新 ☞ YOLOv…

综合评价算法 | Matlab实现基于AHP层次分析法的综合评价算法

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 综合评价算法 | Matlab实现基于AHP层次分析法的综合评价算法 研究内容 AHP的主要特点是通过建立递阶层次结构,把人类的判断转化到若干因 素两两之间重要度的比较上,从而把难于量化的定性判断转化为可操作…

测试四—测试分类

一、按测试对象划分 1.1 界面测试 界面测试&#xff08;简称UI测试)&#xff0c;指按照界面的需求&#xff08;一般是UI设计稿&#xff09;和界面的设计规则&#xff0c;对我们软件界面所展示的全部内容进行测试和检查&#xff0c;一般包括如下内容&#xff1a; 验证界面内容…

解决:在微服务中一个服务访问另一个服务的类或方法出现的问题

我的需求&#xff1a; 我需要在用户模块使用公共模块的service和mapper和实体类&#xff0c;出现以下错误 ​ springboot启动错误如下&#xff1a; 报错结果&#xff1a;需要一个类型为“com.buba.yka.mapper.salesmanMapper”的bean&#xff0c;但找不到该bean Error starti…

接口自动化面试题【思路分享】

文末免费领资料 接口自动化流程怎么做的&#xff0c;框架怎么搭建的&#xff1f; 流程&#xff1a; 1、分析需求&#xff0c;确定测试范围 2、搭建自动化测试环境、准备相关测试数据 3、工具选型&#xff0c;搭建测试框架 4、编写用例 5、执行用例&#xff0c;生成测试报…

记录好项目D19

记录好项目 你好呀&#xff0c;这里是我专门记录一下从某些地方收集起来的项目&#xff0c;对项目修改&#xff0c;进行添砖加瓦&#xff0c;变成自己的闪亮项目。修修补补也可以成为毕设哦 本次的项目是个网上商城管理系统 一、系统介绍 需求设计主要参考天猫商城的购物流…

【Linux】—— 进程的环境变量

序言&#xff1a; 在上期我们已经对进程PCB以及进程状态进行了详细的解释说明。今天&#xff0c;我将带领大家学习的是关于进程的环境变量的问题。 目录 &#xff08;一&#xff09;孤儿进程 1、基本介绍 2、代码演示 &#xff08;二&#xff09;环境变量 1、基本概念 2…

使用git管理matlab代码

matlab使用git管理代码 设置 Git 源代码管理 - MATLAB & Simulink - MathWorks 中国 在 R2020b 之前&#xff0c;必须安装命令行 Git 客户端&#xff0c;才能使用 Git 合并 MATLAB 中的分支。有关详细信息&#xff0c;请参阅安装命令行 Git 客户端。 1.在 Git 中注册二进…

Groovy系列三 Java SpringBoot 整合 Groovy

目录 一、概述 一、在Java中使用Groovy&#xff1a; 二、在Groovy中使用Java&#xff1a; 三、几种范式的不同、优缺点 Java调用Groovy的类和方法&#xff1a; Groovy调用Java的类和方法&#xff1a; 使用GroovyShell执行Groovy脚本&#xff1a; 使用GroovyClassLoader加…

4.0ORBSLAM3之局部建图线程概述

1.简介 局部建图线程是ORBSLAM3的核心线程之一&#xff0c;在初始化SLAM系统时被创建和启动&#xff0c;主要作用是为跟踪线程(跟踪局部地图)以及回环检测线程(回环检测)服务&#xff0c;并进行局部地图优化以及时消除轨迹的累计误差。局部建图线程主要维护一个由共视图Covisi…

JSP网上订餐管理系统用eclipse定制开发mysql数据库BS模式java编程jdbc

一、源码特点 JSP 网上订餐管理系统是一套完善的web设计系统&#xff0c;对理解JSP java SERLVET mvc编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,eclipse开发&#xff0c;数据库为Mysql5.0&a…

java压测工具 Jmeter初使用

一. 下载及安装教程 1. 有博主总结的很好&#xff0c;这里直接放传送门&#xff1a; 【Jmeter】win 10 / win 11&#xff1a;Jmeter 下载、安装、汉化、新机迁移、版本更新&#xff08;Jmeter 4 以上版本均适用&#xff09; 2. Jmeter 自定义创建桌面快捷方式 3. JMeter插件…

手写vue-diff算法(三)updateChildren

前文回顾 上一篇提到&#xff0c;新老儿子节点比对可能存在的 3 种情况及对应的处理方法&#xff1a; 情况 1&#xff1a;老的有儿子&#xff0c;新的没有儿子 处理方法&#xff1a;直接将多余的老dom元素删除即可&#xff1b; 情况 2&#xff1a;老的没有儿子&#xff0c;…

基础知识--客户端·服务端·代理

目录 一、客户端 1.什么是客户端 2.客户端分类 二、服务端 1.什么是服务器 2.服务器的作用 3.服务器工作原理 4.服务器的组成 服务器硬件 服务器软件 5.补充 三、代理 1.代理的分类 正向代理 反向代理 两者的区别与联系 2.总结 一、客户端 1.什么是客户端 …

【八股】【C++】(二)函数、类、模板

这里写目录标题 形参与实参的区别函数调用过程指针和引用当函数参数回调函数友元函数重载匹配运算符重载直接初始化与拷贝初始化函数指针C中struct&#xff08;结构&#xff09;和class&#xff08;类&#xff09;的区别C有哪几种构造函数构造函数的执行顺序析构函数的执行顺序…

设计消息模块的业务层Web层

目录 业务层 一、定义Message业务接口 二、定义Message业务实现类 Web层 一、获取分页消息列表 二、根据ID查询消息 三、把未读消息更新成已读消息 四、删除消息 业务层 一、定义Message业务接口 创建 MessageService.java 类 public interface MessageService {pub…