使用 Redis 实现 RBAC 权限管理

1. 什么是 RBAC?

RBAC(Role-Based Access Control,基于角色的访问控制)是一种常见的权限管理模型,它通过用户(User)角色(Role)权限(Permission) 及其映射关系来控制访问权限。RBAC 的基本思路是:

  1. 用户被分配一个或多个角色;
  2. 每个角色拥有一定的权限;
  3. 通过用户所属角色来决定其是否有权限访问某个资源。

2. 为什么使用 Redis 实现 RBAC?

在传统的 RBAC 设计中,权限数据通常存储在 数据库(如 MySQL),但这种方式可能存在以下问题:

  • 查询性能低:每次鉴权都需要查询多张表,影响 API 响应速度;
  • 不适用于高并发:数据库连接池有限,在高并发场景下可能成为瓶颈;
  • 权限变更不灵活:数据库方案通常需要定期同步缓存,否则变更不会立即生效。

使用 Redis 作为 RBAC 权限存储的优势:

  • 高性能:Redis 作为内存数据库,查询速度极快;
  • 低延迟:可以直接 O(1) 查询权限数据,而无需复杂的 SQL 语句;
  • 支持动态权限变更:用户权限变更可以实时生效,而不需要等待数据库更新;
  • 适用于分布式系统:多台服务器可以共享 Redis 权限数据,避免不同实例状态不一致的问题。

3. 设计 RBAC 数据结构

我们使用 Redis 作为权限存储,并设计以下 Key 结构:

KeyValue说明
user_roles:{user_id}["admin", "editor"]用户的角色列表
role_permissions:{role}["read", "write", "delete"]角色的权限列表
permission_routes:{permission}["GET:/users", "POST:/articles"]权限对应的 API
blacklist_tokens存储已注销的 Token使 JWT 失效,支持主动登出

4. 代码实现

我们使用 Gin 作为 Web 框架,并结合 Redis 进行权限管理。

📌 4.1 安装依赖

go get -u github.com/gin-gonic/gin
go get -u github.com/golang-jwt/jwt/v5
go get -u github.com/redis/go-redis/v9

📌 4.2 初始化 Redis

package mainimport ("context""fmt""log""github.com/redis/go-redis/v9"
)// 初始化 Redis 客户端
var ctx = context.Background()
var redisClient = redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379", // 连接 Redis
})// 初始化 RBAC 角色 & 权限映射
func setupRBAC() {// 角色 → 权限redisClient.SAdd(ctx, "role_permissions:admin", "read", "write", "delete")redisClient.SAdd(ctx, "role_permissions:editor", "read", "write")redisClient.SAdd(ctx, "role_permissions:viewer", "read")// 权限 → APIredisClient.SAdd(ctx, "permission_routes:read", "GET:/users", "GET:/articles")redisClient.SAdd(ctx, "permission_routes:write", "POST:/articles", "PUT:/articles")redisClient.SAdd(ctx, "permission_routes:delete", "DELETE:/articles")// 用户 → 角色redisClient.SAdd(ctx, "user_roles:1", "admin")redisClient.SAdd(ctx, "user_roles:2", "editor")redisClient.SAdd(ctx, "user_roles:3", "viewer")log.Println("RBAC 权限映射初始化完成")
}

📌 4.3 生成 JWT 令牌

package mainimport ("fmt""time""github.com/golang-jwt/jwt/v5"
)// JWT 密钥
var jwtSecret = []byte("supersecretkey")// 生成 JWT 令牌
func GenerateJWT(userID int) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"user_id": userID,"exp":     time.Now().Add(24 * time.Hour).Unix(), // 24 小时有效})return token.SignedString(jwtSecret)
}// 解析 JWT 令牌
func ParseJWT(tokenString string) (int, error) {token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {return jwtSecret, nil})if err != nil || !token.Valid {return 0, fmt.Errorf("invalid token")}claims, ok := token.Claims.(jwt.MapClaims)if !ok {return 0, fmt.Errorf("invalid claims")}return int(claims["user_id"].(float64)), nil
}

📌 4.4 鉴权中间件

// 访问权限检查
func hasAccess(userID int, method, path string) bool {// 1. 获取用户角色roles, err := redisClient.SMembers(ctx, fmt.Sprintf("user_roles:%d", userID)).Result()if err != nil || len(roles) == 0 {return false}// 2. 遍历角色,获取权限for _, role := range roles {permissions, _ := redisClient.SMembers(ctx, fmt.Sprintf("role_permissions:%s", role)).Result()for _, permission := range permissions {routes, _ := redisClient.SMembers(ctx, fmt.Sprintf("permission_routes:%s", permission)).Result()for _, route := range routes {if route == fmt.Sprintf("%s:%s", method, path) {return true}}}}return false
}// RBAC 中间件
func RBACMiddleware() gin.HandlerFunc {return func(c *gin.Context) {tokenString := c.GetHeader("Authorization")if tokenString == "" {c.JSON(401, gin.H{"error": "未提供 Token"})c.Abort()return}// 解析 JWTuserID, err := ParseJWT(tokenString)if err != nil {c.JSON(401, gin.H{"error": "Token 无效"})c.Abort()return}// 检查权限if !hasAccess(userID, c.Request.Method, c.FullPath()) {c.JSON(403, gin.H{"error": "无访问权限"})c.Abort()return}c.Set("userID", userID)c.Next()}
}

📌 4.5 API 接口

func main() {r := gin.Default()setupRBAC()// 登录r.POST("/login", func(c *gin.Context) {userID := 1 // 假设用户 1 登录token, _ := GenerateJWT(userID)c.JSON(200, gin.H{"token": token})})// 受保护 APIapi := r.Group("/api", RBACMiddleware())api.GET("/users", func(c *gin.Context) {c.JSON(200, gin.H{"message": "获取用户列表"})})api.POST("/articles", func(c *gin.Context) {c.JSON(200, gin.H{"message": "创建文章"})})api.DELETE("/articles", func(c *gin.Context) {c.JSON(200, gin.H{"message": "删除文章"})})r.Run(":8080")
}

5. 方案总结

Redis 存权限(推荐):高效、适用于分布式
RBAC 权限映射:角色权限映射清晰
JWT 认证:无状态,适用于 API 认证

这样,你就能 用 Redis 设计一套高效的 RBAC 权限管理,并支持 API 映射!🔥

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

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

相关文章

qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene

qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene code review! 文章目录 qt-C++笔记之QGraphicsScene和 QGraphicsView中setScene、通过scene得到view、通过view得scene1.`setScene` 方法2.通过 `scene` 获取它的视图 (`views()`)…

DeepSeek频繁宕机应对方案

第三方监测显示,38%的企业因AI工具不稳定错失热点流量(Gartner 2025)。当竞品1小时内发布300篇行业内容时,你可能还在为「服务器繁忙」提示焦头烂额。147SEO系统通过智能容错机制,帮助某本地生活平台稳定输出580篇地域…

CentOS/RHEL如何更换国内Yum源

在国内使用CentOS或RHEL系统时,默认的Yum源是国外的,这可能导致软件包的下载速度慢,甚至出现连接超时的问题。为了解决这个问题,我们可以将Yum源切换到国内的镜像源,从而大大提高软件包的下载速度和稳定性。 本文将详…

cs224w课程学习笔记-第2课

cs224w课程学习笔记-第2课 传统图学习 前言一、节点任务1、任务背景2、特征节点度3、特征节点中心性3.1 特征向量中心性(Eigenvector Centrality)3.2 中介中心性(Betweenness Centrality)3.3 接近中心性(Closeness Cen…

【设计模式】【结构型模式】代理模式(Proxy)

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD 🔥 2025本人正在沉淀中… 博客更新速度 👍 欢迎点赞、收藏、关注,跟上我的更新节奏 🎵 当你的天空突…

平板作为电脑拓展屏

有线串流(速度更快) spacedesk 打开usb对安卓的连接 用usb线直接连接电脑和平板 无线串流(延迟高,不推荐) todesk pc和手机端同时下载软件,连接后可以进行远程控制或扩展屏幕 spacedesk 连接到同一个…

[文末数据集]ML.NET库学习010:URL是否具有恶意性分类

文章目录 ML.NET库学习010:URL是否具有恶意性分类项目主要目的和原理项目概述主要功能和步骤总结数据集地址ML.NET库学习010:URL是否具有恶意性分类 项目主要目的和原理 项目主要目的: 本项目的目的是通过分析URL的特征,构建一个机器学习模型来判断给定的URL是否具有恶意…

Zotero PDF Translate插件配置百度翻译api

Zotero PDF Translate插件可以使用几种翻译api,虽然谷歌最好用,但是由于众所周知的原因,不稳定。而cnki有字数限制,有道有时也不行。其他的翻译需要申请密钥。本文以百度为例,进行申请 官方有申请教程: Zot…

具身智能在智能巡检机器人中的应用——以开关柜带电操作机器人为例

随着机器人技术和人工智能的迅速发展,具身智能在各行业的应用日益广泛,尤其是在电力行业中的智能巡检领域。传统的电力巡检和维护工作通常需要人工操作,存在着高温、高压、强电磁场等危险环境,且效率较低。开关柜带电操作机器人作…

网络工程师 (43)IP数据报

前言 IP数据报是互联网传输控制协议(Internet Protocol,IP)的数据报格式,由首部和数据两部分组成。 一、首部 IP数据报的首部是控制部分,包含了数据报传输和处理所需的各种信息。首部可以分为固定部分和可变部分。 固定…

【SpringBoot苍穹外卖】debugDay0 打开前端页面

在某一天学完后,电脑关机,再打开啥都忘了,记起来一点点,前端页面打不开,后端控制台一直循环出错。原来是下面这样哈哈。 查看端口是否被别的程序占用的操作步骤 winR输入cmd打开命令行 netstat -ano | findstr "8…

docker 运行 芋道微服务

jar包打包命令 mvn clean install package -Dmaven.test.skiptrue创建文件夹 docker-ai 文件夹下放入需要jar包的文件夹及 docker-compose.yml 文件 docker-compose.yml 内容:我这里的是ai服务,所以将原先的文件内容做了变更,你们需要用到什…

MySQL-事务隔离级别

事务有四大特性(ACID):原子性,一致性,隔离性和持久性。隔离性一般在事务并发的时候需要保证事务的隔离性,事务并发会出现很多问题,包括脏写,脏读,不可重复读,…

【MediaTek】 T750 openwrt-23.05编 cannot find dependency libexpat for libmesode

MediaTek T750 T750 采用先进的 7nm 制程,高度集成 5G 调制解调器和四核 Arm CPU,提供较强的功能和配置,设备制造商得以打造精巧的高性能 CPE 产品,如固定无线接入(FWA)路由器和移动热点。 MediaTek T750 平台是一款综合的芯片组,集成了 5G SoC MT6890、12nm 制程…

五十天精通硬件设计第32天-S参数

系列文章传送门 50天精通硬件设计第一天-总体规划-CSDN博客 目录 1. S参数基础 2. S参数在信号完整性中的作用 3. 单端 vs. 差分S参数 4. S参数的关键特性 5. S参数的获取与使用 6. S参数分析中的常见问题 7. 实际案例:PCIe通道分析 8. 工具推荐 总结 信号完整性中…

pytest asyncio 支持插件 pytest-asyncio

pytest 是 Python 测试框架,但其不支持基于 asyncio 的异步程序(例如,测试 FastAPI 异步代码),pytest-asyncio 是一个 pytest 插件,该插件赋予 pytest 可以测试使用 asyncio 库代码的能力。 https://github…

Transformer以及BERT阅读参考博文

Transformer以及BERT阅读参考博文 Transformer学习: 已有博主的讲解特别好了: 李沐:Transformer论文逐段精读【论文精读】_哔哩哔哩_bilibili知乎:Transformer模型详解(图解最完整版) - 知乎 个人杂想&…

分享一款AI绘画图片展示和分享的小程序

🎨奇绘图册 【开源】一款帮AI绘画爱好者维护绘图作品的小程序 查看Demo 反馈 github 文章目录 前言一、奇绘图册是什么?二、项目全景三、预览体验3.1 截图示例3.2 在线体验 四、功能介绍4.1 小程序4.2 服务端 五、安装部署5.1 快速开始~~5.2 手动部…

【R语言】回归分析与判别分析

一、线性回归分析 1、lm()函数 lm()函数是用于拟合线性模型(Linear Models)的主要函数。线性模型是一种统计方法,用于描述一个或多个自变量(预测变量、解释变量)与因变量(响应变量)之间的关系…

Visual Studio Code支持WSL,直接修改linux/ubuntu中的文件

步骤1 开始通过 WSL 使用 VS Code | Microsoft Learn 点击远程开发扩展包。 步骤2 Remote Development - Visual Studio Marketplace 点击install, 允许打开Visual Studio Code。 步骤3 共有4项,一齐安装。 步骤4 在WSL Linux(Ubuntu)中&#xf…