SpringBoot实现JWT token自动续期的示例代码

为什么要 token自动续期

token中一般会包含用户的基本信息,为了保证token的安全性,一般会将token的过期时间设置的比较短,但是这样会导致用户因为token过期需要频繁登录,因此需要token自动续期。

 //创建token
String token = JwtUtil.createToken(sysUser.getId(), user.getUserName());
//将token放入redis中,key为用户的手机号+"token"
redisUtil.set(sysUser.getPhone() + GlobalConstant.TOKEN, token, JwtUtil.EXPIRE_TIME*2);

在拦截器中重写public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)方法

/**
 * token自动续期
 *
 * @param sysUser 用户实体
 * @return 是否刷新成功
 */
private boolean refreshToken(SysUser sysUser) {
    String token = request.getHeader(GlobalConstant.TOKEN);
    String cacheToken = (String) (redisUtil.get(sysUser.getPhone() + GlobalConstant.TOKEN));
    //请求头中不存在token,返回false
    if (StringUtil.isEmpty(token)) {
        logger.error("请求头中token不存在");
        return false;
    }
    //用户是否登录只根据redis中token是否存在决定,redis中不存在token,返回false
    if (StringUtil.isEmpty(cacheToken)) {
        logger.error("用户未登录");
        return false;
    }
    try {
        //验证请求头中的token是否合法
        JwtUtil.verify(token);
    } catch (TokenExpiredException tokenExpiredException) {
        /*若抛出token过期异常,检查请求头中的token与redis中的token是否相同
        如果相同,说明用户仍在操作,只是请求头中的token已经过期,此时需要对token进行续期*/
        if (cacheToken.equals(token)) {
            //重新刷新redis中的token的过期时间
            redisUtil.set(sysUser.getPhone() + GlobalConstant.TOKEN, token, JwtUtil.EXPIRE_TIME * 2);
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        //若抛出除token过期异常之外的其他异常,说明该token不合法
        logger.error("token不合法");
        return false;
    }
    return true;
}

拦截器所有代码如下

@Component
public class LoginInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private HttpServletRequest request;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        logger.info("进入拦截器 uri:" + request.getRequestURI());
        // 不是controller的方法不拦截
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        //检查方法上是否有@PreAuth注解,没有则不拦截
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        PreAuth preAuth = handlerMethod.getMethodAnnotation(PreAuth.class);
        if (preAuth == null) {
            return true;
        }
        Long userId = JwtUtil.getUserIdByToken(request);
        SysUser sysUser = sysUserDao.selectById(userId);
        //用户不存在,进行拦截
        if (sysUser == null) {
            logger.error("用户不存在");
            return false;
        }
        if (!refreshToken(sysUser)) {
            return false;
        }
        //判断用户是否有对应权限
        Set<String> authList = this.sysUserDao.queryAuthList(userId);
        if (!authList.contains(preAuth.value())) {
            logger.error("无权限");
            return false;
        }
        return true;
    }

    /**
     * token自动续期
     *
     * @param sysUser 用户实体
     * @return 是否刷新成功
     */
    private boolean refreshToken(SysUser sysUser) {
        String token = request.getHeader(GlobalConstant.TOKEN);
        String cacheToken = (String) (redisUtil.get(sysUser.getPhone() + GlobalConstant.TOKEN));
        //请求头中不存在token,返回false
        if (StringUtil.isEmpty(token)) {
            logger.error("请求头中token不存在");
            return false;
        }
        //用户是否登录只根据redis中token是否存在决定,redis中不存在token,返回false
        if (StringUtil.isEmpty(cacheToken)) {
            logger.error("用户未登录");
            return false;
        }
        try {
            //验证请求头中的token是否合法
            JwtUtil.verify(token);
        } catch (TokenExpiredException tokenExpiredException) {
            /*若抛出token过期异常,检查redis中的是否存在token以及请求头中的token与redis中的token是否相同
            如果相同,说明用户仍在操作,只是请求头中的token已经过期,此时需要对token进行续期*/
            if (cacheToken.equals(token)) {
                //重新刷新redis中的token的过期时间
                redisUtil.set(sysUser.getPhone() + GlobalConstant.TOKEN, token, JwtUtil.EXPIRE_TIME * 60 * 2);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            //若抛出除token过期异常之外的其他异常,说明该token不合法
            logger.error("token不合法");
            return false;
        }
        return true;
    }
}

JwtUtil工具类如下

import com.admin.common.constant.GlobalConstant;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;

public class JwtUtil {
    /**
     * token私钥,不可以暴露
     */
    public static final String TOKEN_SECRET_KEY = "tokenSecretKey";
    /**
     * token过期时间(秒)
     */
    public static final int EXPIRE_TIME = 60;

    /**
     * 创建token
     *
     * @param userId   用户ID
     * @param userName 用户名
     * @return token
     */
    public static String createToken(Long userId, String userName) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, EXPIRE_TIME);
        return JWT.create()
                //签发对象
                .withAudience(userId + "")
                //载荷
                .withClaim("userName", userName)
                //签发时间
                .withIssuedAt(new Date())
                //有效时间
                .withExpiresAt(calendar.getTime())
                //加密
                .sign(Algorithm.HMAC256(TOKEN_SECRET_KEY));
    }

    /**
     * 验证token合法性
     *
     * @param token token
     * @return token是否合法
     */
    public static void verify(String token) {
        JWT.require(Algorithm.HMAC256(TOKEN_SECRET_KEY)).build().verify(token);
    }

  /**
     * 通过token获取userId
     *
     * @return userId
     */
    public static Long getUserIdByToken(HttpServletRequest request) {
        String token = request.getHeader(GlobalConstant.TOKEN);
        String userId = JWT.decode(token).getAudience().get(0);
        return Long.valueOf(userId);
    }
}

到此这篇关于SpringBoot实现JWT token自动续期的示例代码的文章就介绍到这了,更多相关SpringBoot JWT token自动续期内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot整合JWT框架,解决Token跨域验证问题

    一.传统Session认证 1.认证过程 1.用户向服务器发送用户名和密码. 2.服务器验证后在当前对话(session)保存相关数据. 3.服务器向返回sessionId,写入客户端 Cookie. 4.客户端每次请求,需要通过 Cookie,将 sessionId 回传服务器. 5.服务器收到 sessionId,验证客户端. 2.存在问题 1.session保存在服务端,客户端访问高并发时,服务端压力大. 2.扩展性差,服务器集群,就需要 session 数据共享. 二.JWT简介 JWT

  • springboot+jwt实现token登陆权限认证的实现

    一 前言 此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程:对小项目而已是个轻量级的认证机制,符合开发需求: 二 jwt实现登陆认证流程 用户使用账号和面发出post请求 服务器接受到请求后使用私钥创建一个jwt,这边会生成token 服务器返回这个jwt给浏览器 浏览器需要将带有token的jwt放入请求头 每次手到客户端请求,服务器验证该jwt的token 验证成功返回

  • SpringBoot JWT实现token登录刷新功能

    目录 1. 什么是JWT 2. JWT组成部分 3. JWT加密方式 4.实战 5.总结 1. 什么是JWT Json web token (JWT) 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准.简答理解就是一个身份凭证,用于服务识别. JWT本身是无状态的,这点有别于传统的session,不在服务端存储凭证.这种特性使其在分布式场景,更便于扩展使用. 2. JWT组成部分 JWT有三部分组成,头部(header),载荷(payload),是签名(signature). 头

  • SpringBoot-JWT生成Token和拦截器的使用(访问受限资源)

    目录 1.什么是JWT 2.JWT生成token 2.1 添加依赖 2.2 生成token 2.3 使用拦截器解析token 1.什么是JWT JWT官方的定义是:JSON Web令牌(JWT)是一个开放标准(RFC 7519),用于作为JSON对象在各方之间安全地传输信息. 可以验证和信任该信息,因为它是数字签名的. jwt可以使用一个秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名. 其实他本质上就是一个签名,用于验证用户是否可以请求受限资源(例如在商城中向服务器请求个

  • SpringBoot集成JWT实现token验证的流程

    JWT官网: https://jwt.io/ JWT(Java版)的github地址:https://github.com/jwtk/jjwt 什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息.因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名. JWT请求流程 1. 用户使

  • SpringBoot整合JWT Token的完整步骤

    目录 背景 一  JWT 消息构成 1.1 组成 1.2 header 1.3 playload 1.4 signature 二 Spring Boot 和 JWT集成实例 2.1 项目依赖 2.2 自定义注解 @JwtToken 2.3 JWT认证工具类 JwtUtil.java 2.4 拦截器拦截带有注解的接口 JwtInterceptor.java 2.5 全局异常捕获 2.6 接口 JwtController.java 2.7 Postman测试接口 2.7.1 在没有token的情况下

  • 基于springboot+jwt实现刷新token过程解析

    前一段时间讲过了springboot+jwt的整合,但是因为一些原因(个人比较懒)并没有更新关于token的刷新问题,今天跟别人闲聊,聊到了关于业务中token的刷新方式,所以在这里我把我知道的一些点记录一下,也希望能帮到一些有需要的朋友,同时也希望给我一些建议,话不多说,上代码! 1:这种方式为在线刷新,比方说设定的token有效期为30min,那么每次访问资源时,都会在拦截器中去判断一下token是否过期,如果没有过期就刷新token的时间为30min,反之则会重新登录,需要注意的是这种方式

  • 实战SpringBoot集成JWT实现token验证

    目录 环境搭建 1.新建一个SpringBoot项目Jwt-Demo,引入项目后面需要用到的jar包 2.数据库结构 3.配置文件application.properties 4.Entity包下新建一个User类 5.Dao包下新建一个UserDao 6.Service包下新建一个USerService 7.UseService的实现类UserServiceImp 8.controller包下新建一个UserController 9.在resource文件夹下新建一个Usermapper文件

  • SpringBoot实现JWT token自动续期的示例代码

    为什么要 token自动续期 token中一般会包含用户的基本信息,为了保证token的安全性,一般会将token的过期时间设置的比较短,但是这样会导致用户因为token过期需要频繁登录,因此需要token自动续期. //创建token String token = JwtUtil.createToken(sysUser.getId(), user.getUserName()); //将token放入redis中,key为用户的手机号+"token" redisUtil.set(sys

  • Spring Boot实现JWT token自动续期的实现

    1.为什么要 token自动续期 token中一般会包含用户的基本信息,为了保证token的安全性,一般会将token的过期时间设置的比较短,但是这样会导致用户因为token过期需要频繁登录,因此需要token自动续期. 2.如何实现token自动续期 登录时将token存入redis中,缓存有效期设置为 token有效时间的两倍(比token有效时间长即可). //创建token String token = JwtUtil.createToken(sysUser.getId(), user.

  • SpringSecurity Jwt Token 自动刷新的实现

    功能需求 最近项目中有这么一个功能,用户登录系统后,需要给 用户 颁发一个 token ,后续访问系统的请求都需要带上这个 token ,如果请求没有带上这个 token 或者 token 过期了,那么禁止访问系统.如果用户一直访问系统,那么还需要自动延长 token 的过期时间. 功能分析 1.token 的生成 使用现在比较流行的 jwt 来生成. 2.token 的自动延长 要实现 token 的自动延长,系统给用户 颁发 一个 token 无法实现,那么通过变通一个,给用户生成 2个 t

  • SpringBoot整合screw实现数据库文档自动生成的示例代码

    有时候数据库文档需要整理,可是只能手动的复制粘贴,心中一万只草泥马奔腾而过... screw 简洁好用的数据库表结构文档生成工具. 1. 创建项目 1.1 pom.xml <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>

  • SpringBoot结合Redis实现接口幂等性的示例代码

    目录 介绍 实现过程 引入 maven 依赖 spring 配置文件写入 引入 Redis 自定义注解 token 的创建和实现 拦截器的配置 测试用例 介绍 幂等性的概念是,任意多次执行所产生的影响都与一次执行产生的影响相同,按照这个含义,最终的解释是对数据库的影响只能是一次性的,不能重复处理.手段如下 数据库建立唯一索引 token机制 悲观锁或者是乐观锁 先查询后判断 小小主要带你们介绍Redis实现自动幂等性.其原理如下图所示. 实现过程 引入 maven 依赖 <dependency>

  • springboot集成CAS实现单点登录的示例代码

    最近新参与的项目用到了cas单点登录,我还不会,这怎么能容忍!空了学习并搭建了一个spring-boot 集成CAS 的demo.实现了单点登录与登出. 单点登录英文全称是:Single Sign On,简称SSO. 含义:在多个相互信任的系统中,只要登录一个系统其他系统均可访问. CAS 是一种使用广泛的单点登录实现,分为客户端CAS Client和服务端 CAS Service,客户端就是我们的系统,服务端是认证中心,由CAS提供,我们需要稍作修改,启动起来就可以用.~~~~ 效果演示 ht

  • SpringBoot+Netty+WebSocket实现消息发送的示例代码

    一.导入Netty依赖 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.25.Final</version> </dependency> 二.搭建websocket服务器 @Component public class WebSocketServer { /** * 主线程池 */

  • springboot多数据源配置及切换的示例代码详解

    注:本文的多数据源配置及切换的实现方法是,在框架中封装,具体项目中配置及使用,也适用于多模块项目 配置文件数据源读取 通过springboot的Envioment和Binder对象进行读取,无需手动声明DataSource的Bean yml数据源配置格式如下: spring: datasource: master: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url:

  • SpringBoot+MyBatis+AOP实现读写分离的示例代码

    目录 一. MySQL 读写分离 1.1.如何实现 MySQL 的读写分离? 1.2.MySQL 主从复制原理? 1.3.MySQL 主从同步延时问题(精华) 二.SpringBoot+AOP+MyBatis实现MySQL读写分离 2.1.AbstractRoutingDataSource 2.2.如何切换数据源 2.3.如何选择数据源 三 .代码实现 3.0.工程目录结构 3.1.引入Maven依赖 3.2.编写配置文件,配置主从数据源 3.3.Enum类,定义主库从库 3.4.ThreadL

随机推荐