Redis实现RBAC权限管理

2025-03-11 05:50
文章标签 实现 redis 管理 权限 rbac

本文主要是介绍Redis实现RBAC权限管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Redis实现RBAC权限管理》本文主要介绍了Redis实现RBAC权限管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...

1. 什么是 RBAC?

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

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

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 main

import (
	"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",http://www.chinasem.cn "write", "delete")
	redisClient.SAdd(ctx, "role_permissions:editor", "read", "write")
	redisClient.SAdd(ctx, "role_permissions:viewer", "read")

	// 权限 → API
	redisClient.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")
	redishttp://www.chinasem.cnClient.SAdd(ctx, "user_roles:2", "editor")
	redisClient.SAdd(ctx, "user_roles:3", "viewer")

	log.Println("RBAC 权限映射初始化完成")
}

4.3 生成 JWT 令牌

package main

import (
	"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 鉴权中间件

// 访问权限检查
fChina编程unc 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
	}

	/php/ 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() ginjs.HandlerFunc {
	return func(c *gin.Context) {
		tokenString := c.GetHeader("Authorization")
		if tokenString == "" {
			c.jsON(401, gin.H{"error": "未提供 Token"})
			c.Abort()
			return
		}

		// 解析 JWT
		userID, 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})
	})

	// 受保护 API
	api := 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 映射!

到此这篇关于Redis实现RBAC权限管理的文章就介绍到这了,更多相关Redis RBAC权限内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Redis实现RBAC权限管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153694

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Redis Cluster模式配置

《RedisCluster模式配置》:本文主要介绍RedisCluster模式配置,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录分片 一、分片的本质与核心价值二、分片实现方案对比 ‌三、分片算法详解1. ‌范围分片(顺序分片)‌2. ‌哈希分片3. ‌虚

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

使用jenv工具管理多个JDK版本的方法步骤

《使用jenv工具管理多个JDK版本的方法步骤》jenv是一个开源的Java环境管理工具,旨在帮助开发者在同一台机器上轻松管理和切换多个Java版本,:本文主要介绍使用jenv工具管理多个JD... 目录一、jenv到底是干啥的?二、jenv的核心功能(一)管理多个Java版本(二)支持插件扩展(三)环境隔

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根