百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

【Redis深度专题】「踩坑提升」低版本Jedis兼容Redis的ACL机制

mhr18 2025-03-25 15:29 24 浏览 0 评论

首先,针对于Redis6.0之后,已经可以支持通过ACL的访问控制列表的机制进行控制多个用户进行权限控制访问,并且更加精细的控制权限访问处理模式,更加的偏向于RBAC模型的机制体系。

Redis的ACL是什么?

Redis的ACL(Access Control List)是一种用于访问控制的功能,它允许您对Redis服务器进行细粒度的权限管理和访问控制。通过使用ACL,您可以限制对Redis命令和数据的访问,以保护您的Redis实例免受未经授权的访问和滥用。

Redis的ACL功能提供了以下几个关键方面的控制:

  1. 用户和角色管理:ACL允许您创建和管理多个用户,并为每个用户分配适当的角色。角色定义了用户可以执行的命令和访问的数据范围。
  2. 命令级别的权限控制:您可以为每个角色指定允许执行的命令和禁止执行的命令。这使您能够限制用户对特定命令的访问权限。
  3. 数据级别的权限控制:ACL还允许您为每个角色指定可以访问的数据库和键空间。这使您能够限制用户对特定数据的访问权限。
  4. 密码和认证:ACL允许您为每个用户设置密码,并要求用户在连接到Redis服务器时进行身份验证。这提供了一种基本的身份验证机制,以确保只有经过身份验证的用户才能访问Redis。

通过使用ACL,您可以实现对Redis的细粒度访问控制,确保只有经过授权的用户才能执行特定的命令和访问特定的数据。这有助于提高Redis实例的安全性,并防止未经授权的访问和滥用。

POC调研计划方案

目前公司存在了某种需求问题,需要进行调整和升级Redis版本,并且倾向于通过用户(可以理解为角色)+ 密码的方式进行对于Redis访问的控制。

poc截止到了现在应该是勉强可以了,不过还有一些问题,但是应该是可以实现了,大概使用了4套方案:

  1. 升级整体框架版本整体框架,从而升级客户端版本,后面发现和代码的适配问题会引发很多不必要的坑,以及后续改动量实在太大了,我大概POC花费了2d时间去处理。
  2. 不修改整体框架版本,只修改单纯的客户端版本,我修改了很多源码,以及对应的客户端底库,最后发现对于集群模式的时候会出现很多问题,而且DBS目前才有的应该是集群模式吧,所以暂时放弃了,大概POC花费了1d时间
  3. 升级客户端底层仓库,不修改客户端以及框架,后面我也是在减少项目代码的变化,然后将jedis的底层源码进行修改了,但是发现了发现可以实现,但是改动量实在是太大了,基本上修改了整体的源码仓库才可能性,而且出现了对于so库的仓库的加载的问题,POC花费了2d,工作l量至少需要1w人天。

4. (推荐)全流成改造我们的项目代码,方便所有的redisson和jedis代码进行改造和优化调整,以及jedis的对应兼容acl的用户名认证的代码,以及添加对应的配置实现,并且加入适配的代码即可,从而可以实现对应的对应的兼容ACL模式下的:用户名和密码登录。POC花费了2d,工作量还是比较大,我预测大概至少3-4d的实现改造所有服务的代码(1d)的时间进行自测。

Jedis升级版本功能实现控制

Jedis源码改造原则

在不改造任何版本框架版本的场景下,仅仅进行使用适配的模型和能力进行实现用户名和密码的登陆方式。其中就要用到一个原则就是项目目录与jar包中的文件相同的全限定名的时候,会优先采用项目目录中的类进行加载,从而我们就获得了进行覆盖jedis源码的能力。

覆盖Auth的Jedis操作认证

我们将整个BinaryClient全部拷贝出来,放到我们的项目里面,并且包名必须为:redis.clients.jedis。

面向的类为:
redis.clients.jedis.BinaryClient。在较低版本的源码为:

public void auth(final String password) {
setPassword(password);
sendCommand(AUTH, password);
}

对此,我们需要进行对于高版本的代码变更一下Redis的指令auth从参数角度进行变更即可。

指令修改和代码调整兼容

auth password

变更为支持用户名+密码的认证模式机制

auth userName password

故此我们将代码修改为:

public void auth(final String password) {
String userName = RedisUserName.redisUserName;
if(StringUtils.isNotBlank(userName)){
setPassword(password);
sendCommand(AUTH,userName, password);
}
else {
setPassword(password);
sendCommand(AUTH, password);
}
}

此外还考虑了兼容单独密码的模式,所以进行调整了兼容两种模式都共存的if语句,嘻嘻。

这样子将底层的功能进行直接获取用户名进行控制,减少了很多的开发量问题。并且对于Spring框架、甚至我们自己的框架都是透明化的问题。

Redis用户名的传输和配置

接下来就是最后一个问题,配置用户名以及如何传递给他,我在这里使用了一个简单的方案就是通过静态变量进行传输。方便我们全局访问!

在这里插入图片描述

从下面的配置可以看到,我们属于使用RedisUserName类进行访问此类的redisUserName变量进行访问。那么这个值是怎么来的?

直接上源码干货

不说太多其他的,直接上干货即可。

@Component
public class RedisUserName implements BeanPostProcessor {
public static String redisUserName;
@Value("${spring.redis.userName:root}")
private String userName;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof RedisConfig && StringUtils.isEmpty(redisUserName)){
RedisUserName.class.getClassLoader();
try {
Class.forName(RedisUserName.class.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
RedisUserName.redisUserName = userName;
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(bean instanceof RedisConfig && StringUtils.isEmpty(redisUserName)){
RedisUserName.class.getClassLoader();
try {
Class.forName(RedisUserName.class.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
RedisUserName.redisUserName = userName;
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}

实现了Spring的BeanPostProcessor接口的类的方法。它的作用是在Bean初始化之前对特定的Bean进行处理。

  1. public static String redisUserName;:定义了一个静态的字符串变量redisUserName,用于存储Redis的用户名。
  2. @Value("${spring.redis.userName:root}"):使用Spring的@Value注解,将配置文件中的spring.redis.userName属性的值注入到userName变量中。如果配置文件中没有配置该属性,则默认值为”root”。
  3. postProcessBeforeInitialization方法:这是BeanPostProcessor接口的一个方法,用于在Bean初始化之前进行处理。在这个方法中,首先判断当前处理的Bean是否是RedisConfig类型,并且redisUserName为空。如果满足条件,则执行以下操作:
  • RedisUserName.class.getClassLoader();:这行代码没有实际作用,可能是作者误写或者遗留的无用代码。Class.forName(RedisUserName.class.getName());:通过反射加载RedisUserName类,这行代码也没有实际作用,可能是作者误写或者遗留的无用代码。RedisUserName.redisUserName = userName;:将userName的值赋给redisUserName静态变量,即将配置文件中的spring.redis.userName属性的值赋给redisUserName变量。
  1. 最后,返回BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);,继续执行其他的BeanPostProcessor的处理逻辑。

总结介绍说明

在RedisConfig类的Bean初始化之前,将配置文件中的spring.redis.userName属性的值赋给静态变量redisUserName。这样可以在其他地方通过访问
RedisUserName.redisUserName来获取Redis的用户名。但是代码中的部分内容,如
RedisUserName.class.getClassLoader();和Class.forName(
RedisUserName.class.getName());似乎没有实际作用,可能是作者误写或者遗留的无用代码。

修改配置和调整控制

设置对应的ACL的用户和设置指令

主要用于对应SAAS环境的中用户和我们Redis的ACL是一个概念的用户设计。

增加配置文件中的key或者环境变量

# 主要用于Jedis客户端的连接使用
spring.redis.userName: {用户名}
# 主要用于Redisson客户端的连接使用
redisson.userName: {用户名}

修改对应的配置信息

spring.redis.password:{你在设置ACL的时候所制定的密码}

设置Redis的ACL用户指令

设置用户密码

ACL SETUSER {用户名} on >{你的密码}

设置用户整体操作权限

> acl setuser {用户名} ~* &* +@all

相关推荐

【推荐】一个开源免费、AI 驱动的智能数据管理系统,支持多数据库

如果您对源码&技术感兴趣,请点赞+收藏+转发+关注,大家的支持是我分享最大的动力!!!.前言在当今数据驱动的时代,高效、智能地管理数据已成为企业和个人不可或缺的能力。为了满足这一需求,我们推出了这款开...

Pure Storage推出统一数据管理云平台及新闪存阵列

PureStorage公司今日推出企业数据云(EnterpriseDataCloud),称其为组织在混合环境中存储、管理和使用数据方式的全面架构升级。该公司表示,EDC使组织能够在本地、云端和混...

对Java学习的10条建议(对java课程的建议)

不少Java的初学者一开始都是信心满满准备迎接挑战,但是经过一段时间的学习之后,多少都会碰到各种挫败,以下北风网就总结一些对于初学者非常有用的建议,希望能够给他们解决现实中的问题。Java编程的准备:...

SQLShift 重大更新:Oracle→PostgreSQL 存储过程转换功能上线!

官网:https://sqlshift.cn/6月,SQLShift迎来重大版本更新!作为国内首个支持Oracle->OceanBase存储过程智能转换的工具,SQLShift在过去一...

JDK21有没有什么稳定、简单又强势的特性?

佳未阿里云开发者2025年03月05日08:30浙江阿里妹导读这篇文章主要介绍了Java虚拟线程的发展及其在AJDK中的实现和优化。阅前声明:本文介绍的内容基于AJDK21.0.5[1]以及以上...

「松勤软件测试」网站总出现404 bug?总结8个原因,不信解决不了

在进行网站测试的时候,有没有碰到过网站崩溃,打不开,出现404错误等各种现象,如果你碰到了,那么恭喜你,你的网站出问题了,是什么原因导致网站出问题呢,根据松勤软件测试的总结如下:01数据库中的表空间不...

Java面试题及答案最全总结(2025版)

大家好,我是Java面试陪考员最近很多小伙伴在忙着找工作,给大家整理了一份非常全面的Java面试题及答案。涉及的内容非常全面,包含:Spring、MySQL、JVM、Redis、Linux、Sprin...

数据库日常运维工作内容(数据库日常运维 工作内容)

#数据库日常运维工作包括哪些内容?#数据库日常运维工作是一个涵盖多个层面的综合性任务,以下是详细的分类和内容说明:一、数据库运维核心工作监控与告警性能监控:实时监控CPU、内存、I/O、连接数、锁等待...

分布式之系统底层原理(上)(底层分布式技术)

作者:allanpan,腾讯IEG高级后台工程师导言分布式事务是分布式系统必不可少的组成部分,基本上只要实现一个分布式系统就逃不开对分布式事务的支持。本文从分布式事务这个概念切入,尝试对分布式事务...

oracle 死锁了怎么办?kill 进程 直接上干货

1、查看死锁是否存在selectusername,lockwait,status,machine,programfromv$sessionwheresidin(selectsession...

SpringBoot 各种分页查询方式详解(全网最全)

一、分页查询基础概念与原理1.1什么是分页查询分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难...

《战场兄弟》全事件攻略 一般事件合同事件红装及隐藏职业攻略

《战场兄弟》全事件攻略,一般事件合同事件红装及隐藏职业攻略。《战场兄弟》事件奖励,事件条件。《战场兄弟》是OverhypeStudios制作发行的一款由xcom和桌游为灵感来源,以中世纪、低魔奇幻为...

LoadRunner(loadrunner录制不到脚本)

一、核心组件与工作流程LoadRunner性能测试工具-并发测试-正版软件下载-使用教程-价格-官方代理商的架构围绕三大核心组件构建,形成完整测试闭环:VirtualUserGenerator(...

Redis数据类型介绍(redis 数据类型)

介绍Redis支持五种数据类型:String(字符串),Hash(哈希),List(列表),Set(集合)及Zset(sortedset:有序集合)。1、字符串类型概述1.1、数据类型Redis支持...

RMAN备份监控及优化总结(rman备份原理)

今天主要介绍一下如何对RMAN备份监控及优化,这里就不讲rman备份的一些原理了,仅供参考。一、监控RMAN备份1、确定备份源与备份设备的最大速度从磁盘读的速度和磁带写的带度、备份的速度不可能超出这两...

取消回复欢迎 发表评论: