Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >ruoyi-vue版本(三十)Spring Security 安全框架中token的生成与解析

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

作者头像
一写代码就开心
发布于 2023-07-08 10:51:31
发布于 2023-07-08 10:51:31
1.8K01
代码可运行
举报
文章被收录于专栏:java和pythonjava和python
运行总次数:1
代码可运行

1 使用

1 项目里面添加依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   <!-- Token生成与解析-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

2 写工具类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前后端分离 JWT 登录实践
关于 JWT,松哥之前其实写过相关的教程。最近有小伙伴在微信上发消息,问松哥能不能分析一下若依项目中 JWT 登录流程,因为这个项目现在有不少人将之作为脚手架来开发商业项目。我周末抽空看了下,感觉还蛮简单的,于是整一篇文章和大家分享一下这里的 JWT 登录是咋玩的。 本文我将从如下几个方面来和大家分析: 验证码分析 登录流程分析 认证校验流程分析 好啦,不废话了,咱们开整吧! 1. 准备工作 若依这个项目有单体版的也有微服务版的,我这里以单体版的为例来和小伙伴们分享,微服务版的以后有空了也可以整一篇文章和大
江南一点雨
2022/04/18
7930
前后端分离 JWT 登录实践
springboot第25集:实体类定义规则
VO:View视图对象,用来在页面中展示数据的,页面需要哪些字段属性就添加哪些,查询出来之后赋值操作比PO对象要简单。所以提高性能。
达达前端
2023/10/08
3640
springboot第25集:实体类定义规则
怎么做登陆(单点登陆)功能?
先分析下登陆要做啥 首先,搞清楚要做什么。 登陆了,系统就知道这是谁,他有什么权限,可以给他开放些什么业务功能,他能看到些什么菜单?。。。这是这个功能的目的和存在的意义。 怎么落实? 怎么实现它?用什么实现? 我们的项目是Springboot + Vue前后端分离类型的。 选择用token + redis 实现,权限的话用SpringSecurity来做。 前后端分离避不开的一个问题就是单点登陆,单点登陆咱们有很多实现方式:CAS中央认证、JWT、token等,咱们这种方式其实本身就是基于token的一
科技新语
2023/01/05
2.8K0
各个微服务认证授权的处理方法
1.通过认证授权模块进行登录 在这里我们默认登录都是可以正常获取token令牌的,也就是都是登录成功的 2.微服务网关(SpringGateway) 在该微服务中我们通过拦截器链接请求,通过该请求是排除过滤的 uri 地址(例如:登录请求/auth/login),则放行该请求,否则则进行token认证,在这里我们有2种认证方式: 2.1 网关统一认证授权(本次不介绍该模式) 该模式需要使用redis进行缓存所有的认证路径和所有路径所需要的角色权限信息,最后在网关中统一鉴权,其他微服务不进行鉴权处理。
Reset
2022/12/27
9710
ruoyi-vue版本(四)@PreAuthorize 注解在若依里面的作用,springsecurity 框架相关的配置
我们打开若依项目,发现一些接口上面是有@PreAuthorize 注解,那么这个注解的作用是什么?
一写代码就开心
2023/02/01
1.2K0
让jwt来保护你的接口服务
以前写过一篇关于接口服务规范的文章,原文在此,里面关于安全性问题重点讲述了通过appid,appkey,timestamp,nonce以及sign来获取token,使用token来保障接口服务的安全。今天我们来讲述一种更加便捷的方式,使用jwt来生成token。
Java旅途
2021/08/05
6940
前端系列18集-权限,nginx成功,屏幕分辨率,vue3
添加了sendWebSocketMessage函数,该函数用于向WebSocket服务器发送消息。您可以在需要发送消息的地方调用该函数,并将消息作为参数传递给它。函数会检查WebSocket连接是否已建立,并且连接状态为OPEN时才发送消息。
达达前端
2023/10/08
2710
前端系列18集-权限,nginx成功,屏幕分辨率,vue3
SpringBoot使用Security认证框架(1.加类)
本文章包含Security的认证和授权方法 并且在执行Security之前会执行自已编写的PowerFilter过滤器 而且登录信息会存入Redis,也会从Redis取
蚊子.
2023/08/10
4550
后端生成Token架构与设计详解
目的:Java开源生鲜电商平台-Java后端生成Token目的是为了用于校验客户端,防止重复提交.
好好学java
2020/12/08
1.7K0
Spring Security和JWT实现登录授权认证
IUserService的实现类,注册时会将用户权限设置为ROLE_USER,同时将密码使用BCrypt加密
朝雨忆轻尘
2019/06/18
4.9K2
SpringSecurity学习
其核心就是一组过滤器链,项目启动后将会自动配置。最核心的就是 Basic Authentication Filter 用来认证用户的身份,一个在spring security中一种过滤器处理一种认证方式
云边小卖部
2022/12/02
7980
SpringSecurity结合JwtToken验证(后端部分)
简介:本文在SpringSecurity基础公共之上,整合JwtToken功能,本文是后端部分。
GeekLiHua
2025/01/21
3940
SpringSecurity结合JwtToken验证(后端部分)
基于若依框架扩展微信扫码登录功能-扫码登录实现
PC 端点击微信登录时生成一个 uuid 存入 redis 并弹出一个二维码,二维码地址(附带了生成的 uuid)是移动端的网页,微信扫码后打开的是配置好的网页授权链接,通过网页授权的方式获取 code 拿到用户 openid 后存入redis中,PC 端通过轮询方式根据生成的 uuid 查询用户 openid 进行登录。
薛定喵君
2024/10/07
2K1
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
文章链接:https://cloud.tencent.com/developer/article/2466182
左诗右码
2024/11/18
9810
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
RuoYi框架集成DingDing登录
图片图片图片图片集成概览login.js:api定义钉钉登录接口user.js:在钉钉登录成功后,设置tokenlogin.vue:使用钉钉的默认集成页面进行钉钉登录DingDingService.java(以及它的实现类 DingDingServiceImpl.java):访问钉钉的服务接口SysLoginController.java:定义钉钉登录接口pom.xml:添加钉钉服务依赖jar包SecurityConfig.java:将钉钉登录接口设置为可匿名访问UserDetailsServiceImpl
在下是首席架构师
2023/03/30
3.1K3
RuoYi框架集成DingDing登录
【微服务环境配置JWT】SpringBoot中配置jwt
1. 在微服务父工程中pom文件中引入,jwtToken依赖 <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency> 2. 配置创建JwtToken的工具类 package priv.kuki.utils; import io.
CODER-V
2023/04/06
8500
ruoyi-vue版本(十三)若依项目里面,spring security 框架的使用
这个里面就是验证的逻辑,就是根据前端传过来的用户名密码判数据库是不是有用户,最后如果有,将用户的信息封装为UserDetails对象里面,因为是规定,这个安全框架需要将用户的信息存到这个 对象里面;
一写代码就开心
2023/02/13
1.3K0
ruoyi-vue版本(十三)若依项目里面,spring security 框架的使用
SpringBoot整合Security安全框架、控制权限
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
宁在春
2022/10/31
1K0
SpringBoot整合Security安全框架、控制权限
4万字!Spring Security 从入门到精通!
Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。
一行Java
2023/02/23
7480
4万字!Spring Security 从入门到精通!
微服务网关和Jwt令牌 入门学习!
对于微服架构的项目,不同的微服务会有不同的网络地址, 外部客户端可能需要调用多个服务的接口才能完成一个业务需求, 如果让客户端直接与各个微服务通信,会有以下的问题:
Java_慈祥
2024/08/06
4660
微服务网关和Jwt令牌 入门学习!
推荐阅读
相关推荐
前后端分离 JWT 登录实践
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档