java 拦截器-用户无操作超时退出利用Redis

news2024/10/7 14:24:07

1、授权过滤,只要实现AuthConfigAdapter接口
2、利用Redis token超时时间,用户访问后台续时

效果
在这里插入图片描述

@Component
public class AuthFilter implements Filter {

    private static Logger logger = LoggerFactory.getLogger(AuthFilter.class);

    @Autowired
    private AuthConfigAdapter authConfigAdapter;

    @Autowired(required = false)
    private HttpHandler httpHandler;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        List<String> excludePathPatterns = authConfigAdapter.excludePathPatterns();

        // 如果匹配不需要授权的路径,就不需要校验是否需要授权
        if (CollectionUtil.isNotEmpty(excludePathPatterns)) {
            for (String excludePathPattern : excludePathPatterns) {
                AntPathMatcher pathMatcher = new AntPathMatcher();
                if (pathMatcher.match(excludePathPattern, req.getRequestURI())) {
                    chain.doFilter(req, resp);
                    return;
                }
            }
        }

        String accessToken = req.getHeader("Authorization");
        String sysType = req.getHeader("SysType");
        if (StrUtil.isBlank(accessToken)) {
            logger.error("{} : {}", ResponseEnum.UNAUTHORIZED, req.getRequestURI());
            httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
            return;
        }
        if(StrUtil.isBlank(sysType)){
            logger.error("{} : {}", ResponseEnum.UNAUTHORIZED, req.getRequestURI());
            httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
            return;
        }

        // 校验token,并返回用户信息
        ServerResponseEntity<UserInfoInTokenBO> userInfoInTokenVoServerResponseEntity = TokenSecurity.checkToken(accessToken);
        if (!userInfoInTokenVoServerResponseEntity.isSuccess()) {
            logger.error("{} : {}", ServerResponseEntity.transform(userInfoInTokenVoServerResponseEntity), req.getRequestURI());
            httpHandler.printServerResponseToWeb(ServerResponseEntity.transform(userInfoInTokenVoServerResponseEntity));
            return;
        }
        if(userInfoInTokenVoServerResponseEntity.getData().getSysType() != Integer.parseInt(sysType)){
            httpHandler.printServerResponseToWeb(ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED));
            return;
        }
        AuthUserContext.set(BeanUtil.copyProperties(userInfoInTokenVoServerResponseEntity.getData(), UserInfoInTokenBO.class));

        try {
            chain.doFilter(req, resp);
        } finally {
            AuthUserContext.clean();
        }

    }
}


@Component
@RefreshScope
public class TokenSecurity {

    private static final Logger logger = LoggerFactory.getLogger(TokenSecurity.class);

    private static RedisTemplate<Object, Object> redisTemplate = null;

    private static StringRedisTemplate stringRedisTemplate;

    public TokenSecurity(RedisTemplate<Object, Object> redisTemplate, StringRedisTemplate stringRedisTemplate) {
        TokenSecurity.redisTemplate = redisTemplate;
        TokenSecurity.stringRedisTemplate = stringRedisTemplate;
    }


    public static ServerResponseEntity<UserInfoInTokenBO> checkToken(String accessToken) {
        ServerResponseEntity<UserInfoInTokenBO> userInfoByAccessTokenResponse = getUserInfoByAccessToken(accessToken, true);
        if (!userInfoByAccessTokenResponse.isSuccess()) {
            return ServerResponseEntity.transform(userInfoByAccessTokenResponse);
        }
        return ServerResponseEntity.success(userInfoByAccessTokenResponse.getData());
    }

    public static ServerResponseEntity<UserInfoInTokenBO> getUserInfoByAccessToken(String accessToken, boolean needDecrypt) {
        if (StrUtil.isBlank(accessToken)) {
            return ServerResponseEntity.showFailMsg("accessToken is blank");
        }
        String realAccessToken;
        if (needDecrypt) {
            ServerResponseEntity<String> decryptTokenEntity = decryptToken(accessToken);
            if (!decryptTokenEntity.isSuccess()) {
                return ServerResponseEntity.transform(decryptTokenEntity);
            }
            realAccessToken = decryptTokenEntity.getData();
        }
        else {
            realAccessToken = accessToken;
        }
        UserInfoInTokenBO userInfoInTokenBO = (UserInfoInTokenBO) redisTemplate.opsForValue().get(getAccessKey(realAccessToken));

        if (userInfoInTokenBO == null) {
            return ServerResponseEntity.fail(ResponseEnum.CLEAN_TOKEN);
        }
        String refreshToken = stringRedisTemplate.opsForValue().get(CacheNames.REFRESH_TO_ACCESS + userInfoInTokenBO.getMobile());
        if (StrUtil.isBlank(refreshToken)) {
            return ServerResponseEntity.fail(ResponseEnum.CLEAN_TOKEN);
        }
        // 存在则token续时7200秒
        redisTemplate.opsForValue().getAndExpire(getAccessKey(realAccessToken), 7200L, TimeUnit.SECONDS);
        return ServerResponseEntity.success(userInfoInTokenBO);
    }

    public static String getAccessKey(String accessToken) {
        return CacheNames.ACCESS + accessToken;
    }

    private static ServerResponseEntity<String> decryptToken(String data) {
        String decryptStr;
        String decryptToken;
        try {
            decryptStr = Base64.decodeStr(data);
            decryptToken = decryptStr.substring(0,32);
            // 创建token的时间,token使用时效性,防止攻击者通过一堆的尝试找到aes的密码,虽然aes是目前几乎最好的加密算法
            long createTokenTime = Long.parseLong(decryptStr.substring(32,45));
            // token的过期时间
            int expiresIn = getExpiresIn();
            long second = 1000L;
            if (System.currentTimeMillis() - createTokenTime > expiresIn * second) {
                return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR);
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage());
            return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR);
        }

        // 防止解密后的token是脚本,从而对redis进行攻击,uuid只能是数字和小写字母
        if (!PrincipalUtil.isSimpleChar(decryptToken)) {
            return ServerResponseEntity.fail(ResponseEnum.TOKEN_ERROR);
        }
        return ServerResponseEntity.success(decryptToken);
    }

    private static int getExpiresIn() {
        // 3600秒
        int expiresIn = 3600;

        expiresIn = expiresIn * 24;

        return expiresIn;
    }
}

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

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

相关文章

《python编程从入门到实践》day39

# 昨日知识点回顾 创建主页、继承模版、显示特定主题页面 # view.py from django.shortcuts import render# 导入所需数据相关联的模型 from .models import Topic# Create your views here. def index(request):"""学习笔记的主页"""#…

GB报文中的Cseq值的注意点

一、 问题现象 【问题现象】NVR使用GB接三方平台发现倍速回放时&#xff0c; 【现场拓扑】现场拓扑如下 &#xff08;1&#xff09; NVR侧使用家用宽带的方式&#xff0c;通过国标跨公网接入三方平台。 图1.1&#xff1a;网络拓扑 二、 抓包分析 INVITE sip:420000004013200…

ABC354学习笔记

高桥有一棵植物&#xff0c;这个植物在第 0 0 0 天时高度为 0 c m 0\,\mathrm{cm} 0cm&#xff0c;此后的第 i i i 天&#xff0c;他的植物会增高 2 i c m 2^i\,\mathrm{cm} 2icm。 高桥身高为 H c m H\,\mathrm{cm} Hcm。 高桥想知道在第几天&#xff0c;他的植物的高度会…

grpc、多集群、多租户

gRPC和服务发现 一个A high-performance, open-source universal RPC framework&#xff0c;高性能、开源的通用 RPC 框架。使用protobuf 语言基于文件定义服务&#xff0c;通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub。移动端上面则是基于标准的 HTTP…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(十三)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 我们&#xff0c;继续讲一…

如何将前端项目打包并部署到不同服务器环境

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈&#xff08;笔记是根据b站尚硅谷的前端讲师【张天禹老师】整理的&#xff0c;用于自己复盘&#xff0c;有需要学习的可以去b站学习原版视频&…

three.js判断物体在人的前面,还是后面

three.js判断物体在人的前面&#xff0c;还是后面 const player new THREE.Vectors(10, 0, 5); const mesh new THREE.Vectors(15, 0, 6);上面&#xff0c;两个变量分别表示&#xff0c;玩家的位置&#xff0c;物体的位置。 从这发现&#xff0c;当玩家和物体的角度关系 小…

网络协议——RTSP(简介、搭建RTSP服务器)

一、简介 1、什么是RTSP RTSP&#xff08;Real-Time Streaming Protocol&#xff0c;实时流传输协议&#xff09;是一种网络应用协议&#xff0c;旨在用于在互联网上进行娱乐和通信的实时流媒体的控制。它允许客户端远程控制媒体服务器上的流媒体播放&#xff0c;例如播放、暂…

决定新泽西州版图的关键历史事件

决定新泽西州版图的关键历史事件 1. *民地建立&#xff1a;1664年&#xff0c;新泽西成为英国*民地。该地区原为荷兰*民地的一部分&#xff0c;但同年根据英王查理二世的赐予&#xff0c;转归给了他的兄弟约克公爵&#xff08;后来的詹姆士二世&#xff09;&#xff0c;之后又被…

Matlab 结构光相移法(单频多相)

文章目录 一、简介1、基于点的测距2、基于条纹的测距二、条纹编码2.1 二进制编码2.2相移法三、实现代码参考文献一、简介 在介绍相移法之前,我们需要先了解一下为啥会有相移法,了解了其来龙去脉,则更容易去应用它。 1、基于点的测距 首先我们从点的测距开始,这有点类似于立…

C++笔试强训day33

目录 1.跳台阶扩展问题 2.包含不超过两种字符的最长子串 3.字符串的排列 1.跳台阶扩展问题 链接https://www.nowcoder.com/practice/953b74ca5c4d44bb91f39ac4ddea0fee?tpId230&tqId39750&ru/exam/oj 我是用动态规划解决的&#xff1a; #include <iostream>…

Oracle 并行和 session 数量的

这也就是为什么我们指定parallel为4&#xff0c;而实际并行度为8的原因。 insert create index&#xff0c;发现并行数都是加倍的 Indexes seem always created with parallel degree 1 during import as seen from a sqlfile. The sql file shows content like: CREATE INDE…

【傻呱呱】python安装phook3(Windows端)

前期准备 swig程序Visual Studio C 构建工具 配置swig程序 将下载好的“swig-4.2.1”压缩包解压到C盘从C盘打开“swig-4.2.1”文件夹并复制文件夹路径 在开始菜单里搜索“环境变量”&#xff0c;点击“编辑系统环境变量” 点击“环境变量” 找到“path”并双击 点击“新建” …

K8S认证|CKA题库+答案| 13. sidecar 代理容器日志

目录 13、使用 sidecar 代理容器日志 CKA v1.29.0模拟系统 下载试用 题目&#xff1a; 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、生成yaml文件 3&#xff09;、官网找模板 4&#xff09;、编辑yaml文件 5&#xff09;、应用yaml文件 ​6&…

吉林大学软件工程简答题整理

1.6种软件过程模型列举&#xff0c;及优缺点&#xff08;每个都从时间、质量、过程、本身特点去考虑&#xff09; 瀑布模型 优点缺点V模型 优点&#xff1a;缺点&#xff1a; 原型模型 优点&#xff1a;演化模型 建增模型 优点缺点螺旋模型 优点缺点喷泉模型 RUP、敏捷工程、…

kubernetes(Jenkins、kubernetes核心、K8s实战-KubeSphere、)

文章目录 1. Jenkins1.1. 概述1.1.1. 简单部署1.1.2. 自动化部署1.1.3. DevOps概述1.1.4. CI/CD概述 1.2. jenkins介绍及安装1.2.1. 安装1.2.2. 解锁jenkins1.2.3. 安装推荐插件1.2.4. 创建管理员用户1.2.5. 升级jenkins版本1.2.6. 安装额外插件blue ocean1.2.7. jenkins界面说…

Rust后台管理系统Salvo-admin源码编译

1.克隆salvo-admin后台管理系统源码: https://github.com/lyqgit/salvo-admin.git 2.编译 编译成功 3.创建mysql数据库与执行sql脚本 输入名称ry-vue 执行sql脚本 全部执行上面3个sql 修改数据库用户名与密码: 清理及重新编译 cargo clean cargo build 4.运行并测试 cargo…

【组合数学】常考试题答案

一、单项选择题&#xff08;每小题3分&#xff0c;共15分&#xff09; 1. 用3个“1”和4个“0”能组成&#xff08; &#xff09;个不同的二进制数字。 A. 35 B. 36, C. 37, D. 38 2. 整除300的正整数的个数为&#xff08;  &#xff09;。 A. 14…

【docker】安装harbor出现问题: Running 1/1 ✘ Network harbor_harbor Error

安装harbor出现问题&#xff1a; [] Running 1/1 ✘ Network harbor_harbor Error 0.2s failed to create network harbor_harbor: Error response from daemon: Fa…

STM32F4_HAL_GPIO输入——按键输入

1、按键简介 常态下&#xff0c;独立按键是断开的&#xff0c;按下的时候才闭合。每个独立按键会单独占用一个 IO 口&#xff0c;通过 IO 口的高低电平判断按键的状态。但是按键在闭合和断开的时候&#xff0c;都存在抖动现象&#xff0c;即按键在闭合时不会马上就稳定的连接&a…