aliyun-deepseek-r1
This commit is contained in:
		
							parent
							
								
									998e9d5412
								
							
						
					
					
						commit
						375b305ab4
					
				
							
								
								
									
										221
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								README.md
									
									
									
									
									
								
							| @ -1,221 +0,0 @@ | |||||||
| ### 认证相关路由 |  | ||||||
| 
 |  | ||||||
| 1. **注册用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X POST http://localhost:8080/auth/register \ |  | ||||||
|    -H "Content-Type: application/json" \ |  | ||||||
|    -d '{"username": "testuser", "password": "testpass", "email": "test@example.com"}' |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 2. **登录用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X POST http://localhost:8080/auth/login \ |  | ||||||
|    -H "Content-Type: application/json" \ |  | ||||||
|    -d '{"username": "testuser", "password": "testpass"}' |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| ### 需要认证的路由 |  | ||||||
| 
 |  | ||||||
| 假设登录后返回的token为`your_jwt_token_here`。 |  | ||||||
| 
 |  | ||||||
| #### 用户管理 |  | ||||||
| 
 |  | ||||||
| 3. **获取所有用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X GET http://localhost:8080/api/users \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 4. **获取单个用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X GET http://localhost:8080/api/users/1 \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 5. **更新用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X PUT http://localhost:8080/api/users/1 \ |  | ||||||
|    -H "Content-Type: application/json" \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" \ |  | ||||||
|    -d '{"name": "updated_name", "email": "updated_email@example.com"}' |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 6. **删除用户** |  | ||||||
|    ```sh |  | ||||||
|    curl -X DELETE http://localhost:8080/api/users/1 \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| #### 角色管理 |  | ||||||
| 
 |  | ||||||
| 7. **创建新角色** |  | ||||||
|    ```sh |  | ||||||
|    curl -X POST http://localhost:8080/api/roles \ |  | ||||||
|    -H "Content-Type: application/json" \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" \ |  | ||||||
|    -d '{"name": "admin", "description": "Administrator role"}' |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 8. **获取所有角色** |  | ||||||
|    ```sh |  | ||||||
|    curl -X GET http://localhost:8080/api/roles \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 9. **获取单个角色** |  | ||||||
|    ```sh |  | ||||||
|    curl -X GET http://localhost:8080/api/roles/1 \ |  | ||||||
|    -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|    ``` |  | ||||||
| 
 |  | ||||||
| 10. **更新角色** |  | ||||||
|     ```sh |  | ||||||
|     curl -X PUT http://localhost:8080/api/roles/1 \ |  | ||||||
|     -H "Content-Type: application/json" \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" \ |  | ||||||
|     -d '{"name": "updated_role_name", "description": "Updated description"}' |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| 11. **删除角色** |  | ||||||
|     ```sh |  | ||||||
|     curl -X DELETE http://localhost:8080/api/roles/1 \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| #### 权限管理 |  | ||||||
| 
 |  | ||||||
| 12. **创建新权限** |  | ||||||
|     ```sh |  | ||||||
|     curl -X POST http://localhost:8080/api/permissions \ |  | ||||||
|     -H "Content-Type: application/json" \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" \ |  | ||||||
|     -d '{"name": "create_user", "description": "Create user permission", "resource": "user", "action": "create"}' |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| 13. **获取所有权限** |  | ||||||
|     ```sh |  | ||||||
|     curl -X GET http://localhost:8080/api/permissions \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| 14. **获取单个权限** |  | ||||||
|     ```sh |  | ||||||
|     curl -X GET http://localhost:8080/api/permissions/1 \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| 15. **更新权限** |  | ||||||
|     ```sh |  | ||||||
|     curl -X PUT http://localhost:8080/api/permissions/1 \ |  | ||||||
|     -H "Content-Type: application/json" \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" \ |  | ||||||
|     -d '{"name": "updated_permission_name", "description": "Updated description", "resource": "user", "action": "update"}' |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| 16. **删除权限** |  | ||||||
|     ```sh |  | ||||||
|     curl -X DELETE http://localhost:8080/api/permissions/1 \ |  | ||||||
|     -H "Authorization: Bearer your_jwt_token_here" |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| > 请用curl语句实现如下操作: |  | ||||||
| >  |  | ||||||
| > 创建一个账号: |  | ||||||
| > 	fullname: 李晓,  |  | ||||||
| > 	用户名: lixiao   |  | ||||||
| > 	密码 abcd@1234,  |  | ||||||
| > 	邮箱 lixiao@zjmud.xyz |  | ||||||
| > 创建2个权限: |  | ||||||
| > 	dbGroup1Reader: |  | ||||||
| > 		resource: db1,db2 |  | ||||||
| > 		action: read |  | ||||||
| > 	dbGroup1Writer: |  | ||||||
| > 		resource: db1,db2 |  | ||||||
| > 		action: write |  | ||||||
| > 创建1个角色:  |  | ||||||
| > 	db1RW, 包含Permissions: "dbGroup1Reader, dbGroup1Writer" |  | ||||||
| > 把 账号lixiao绑定角色 db1RW |  | ||||||
| 
 |  | ||||||
| 为了实现这些操作,我们需要使用 `curl` 命令来发送 HTTP 请求到你的 API。假设你的 API 端点是 `http://localhost:8080/api`,以下是具体的 `curl` 命令: |  | ||||||
| 
 |  | ||||||
| ### 1. 创建账号 |  | ||||||
| ```sh |  | ||||||
| curl -X POST http://localhost:8080/auth/register \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '{ |  | ||||||
|     "fullname": "李晓", |  | ||||||
|     "username": "lixiao", |  | ||||||
|     "password": "abcd@1234", |  | ||||||
|     "email": "lixiao@zjmud.xyz" |  | ||||||
| }' |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 2. 创建权限 `dbGroup1Reader` |  | ||||||
| ```sh |  | ||||||
| curl -X POST http://localhost:8080/api/permissions \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '{ |  | ||||||
|     "name": "dbGroup1Reader", |  | ||||||
|     "description": "Read access to db1 and db2", |  | ||||||
|     "resource": "db1,db2", |  | ||||||
|     "action": "read" |  | ||||||
| }' |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 3. 创建权限 `dbGroup1Writer` |  | ||||||
| ```sh |  | ||||||
| curl -X POST http://localhost:8080/api/permissions \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '{ |  | ||||||
|     "name": "dbGroup1Writer", |  | ||||||
|     "description": "Write access to db1 and db2", |  | ||||||
|     "resource": "db1,db2", |  | ||||||
|     "action": "write" |  | ||||||
| }' |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 4. 创建角色 `db1RW` 并包含权限 `dbGroup1Reader` 和 `dbGroup1Writer` |  | ||||||
| 首先,我们需要获取 `dbGroup1Reader` 和 `dbGroup1Writer` 的 ID。假设我们已经知道这些 ID(例如 `readerID` 和 `writerID`),我们可以直接使用它们。如果不知道,可以通过查询权限列表来获取。 |  | ||||||
| 
 |  | ||||||
| #### 查询权限列表以获取 ID(可选) |  | ||||||
| ```sh |  | ||||||
| curl -X GET http://localhost:8080/api/permissions |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### 创建角色 `db1RW` 并关联权限 |  | ||||||
| 假设 `readerID` 是 1,`writerID` 是 2: |  | ||||||
| ```sh |  | ||||||
| curl -X POST http://localhost:8080/api/roles \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '{ |  | ||||||
|     "name": "db1RW", |  | ||||||
|     "description": "Read and Write access to db1 and db2" |  | ||||||
| }' |  | ||||||
| 
 |  | ||||||
| # 获取新创建的角色 ID(假设为 roleID) |  | ||||||
| curl -X GET http://localhost:8080/api/roles |  | ||||||
| 
 |  | ||||||
| # 为角色 `db1RW` 分配权限 `dbGroup1Reader` 和 `dbGroup1Writer` |  | ||||||
| curl -X POST http://localhost:8080/api/roles/{roleID}/permissions \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '[ |  | ||||||
|     {"permission_id": 1}, |  | ||||||
|     {"permission_id": 2} |  | ||||||
| ]' |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### 5. 将账号 `lixiao` 绑定角色 `db1RW` |  | ||||||
| 假设 `lixiao` 的用户 ID 是 1,`db1RW` 的角色 ID 是 1: |  | ||||||
| ```sh |  | ||||||
| curl -X POST http://localhost:8080/api/users/{userID}/roles \ |  | ||||||
| -H "Content-Type: application/json" \ |  | ||||||
| -d '[ |  | ||||||
|     {"role_id": 1} |  | ||||||
| ]' |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| 请根据实际情况替换 `{userID}` 和 `{roleID}` 为实际的 ID 值。 |  | ||||||
| 
 |  | ||||||
| 如果你需要自动化这个过程,可以编写一个脚本来执行这些命令,并处理响应以获取必要的 ID。 |  | ||||||
| 
 |  | ||||||
| * |  | ||||||
| @ -1,55 +1,49 @@ | |||||||
| package api | package api | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/controllers" | 	"gitea.zjmud.com/phyer/rbac/controllers" | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/middleware" | 	"gitea.zjmud.com/phyer/rbac/middleware" | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func SetupRoutes(r *gin.Engine) { | func SetupRouter(db *gorm.DB, redisClient *redis.Client) *gin.Engine { | ||||||
| 	// 认证相关路由 | 	router := gin.Default() | ||||||
| 	auth := r.Group("/auth") | 
 | ||||||
|  | 	// Initialize controllers | ||||||
|  | 	authController := controllers.NewAuthController(db, redisClient) | ||||||
|  | 	rbacController := controllers.NewRBACController(db, redisClient) | ||||||
|  | 	userController := controllers.NewUserController(db, redisClient) | ||||||
|  | 
 | ||||||
|  | 	// Public routes - No authentication required | ||||||
|  | 	authGroup := router.Group("/auth") | ||||||
| 	{ | 	{ | ||||||
| 		auth.POST("/register", controllers.Register) | 		authGroup.POST("/login", authController.Login) | ||||||
| 		auth.POST("/login", controllers.Login) | 		authGroup.POST("/register", authController.Register) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// 需要认证的路由 | 	// Protected routes - Require JWT authentication | ||||||
| 	api := r.Group("/api") | 	apiGroup := router.Group("/api") | ||||||
| 	api.Use(middleware.JWTAuth()) | 	apiGroup.Use(middleware.AuthMiddleware()) | ||||||
| 	{ | 	{ | ||||||
| 		// 用户管理 | 		// User management routes | ||||||
| 		users := api.Group("/users") | 		userGroup := apiGroup.Group("/users") | ||||||
| 		{ | 		{ | ||||||
| 			users.GET("/", controllers.GetUsers) | 			userGroup.GET("", userController.GetUsers) | ||||||
| 			users.GET("/:id", controllers.GetUser) | 			userGroup.GET("/:id", userController.GetUserByID) | ||||||
| 			users.PUT("/:id", controllers.UpdateUser) |  | ||||||
| 			users.DELETE("/:id", controllers.DeleteUser) |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// 角色管理 | 		// RBAC administration routes with additional authorization | ||||||
| 		roles := api.Group("/roles") | 		rbacGroup := apiGroup.Group("/rbac") | ||||||
|  | 		rbacGroup.Use(middleware.RBACMiddleware()) | ||||||
| 		{ | 		{ | ||||||
| 			roles.POST("/", controllers.CreateRole) | 			rbacGroup.POST("/roles", rbacController.CreateRole) | ||||||
| 			roles.GET("/", controllers.GetRoles) | 			rbacGroup.POST("/permissions", rbacController.CreatePermission) | ||||||
| 			roles.GET("/:id", controllers.GetRole) | 			rbacGroup.POST("/resources", rbacController.CreateResource) | ||||||
| 			roles.PUT("/:id", controllers.UpdateRole) | 			rbacGroup.POST("/resource-groups", rbacController.CreateResourceGroup) | ||||||
| 			roles.DELETE("/:id", controllers.DeleteRole) | 			rbacGroup.POST("/actions", rbacController.CreateAction) | ||||||
|  | 			rbacGroup.POST("/assignments", rbacController.AssignRoleToUser) | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 		// 权限管理 | 	return router | ||||||
| 		permissions := api.Group("/permissions") |  | ||||||
| 		{ |  | ||||||
| 			permissions.POST("", controllers.CreatePermission) |  | ||||||
| 			permissions.GET("", controllers.GetPermissions) |  | ||||||
| 			permissions.GET("/:id", controllers.GetPermission) |  | ||||||
| 			permissions.PUT("/:id", controllers.UpdatePermission) |  | ||||||
| 			permissions.DELETE("/:id", controllers.DeletePermission) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Handle trailing slash redirect |  | ||||||
| 		api.GET("/permissions/", func(c *gin.Context) { |  | ||||||
| 			c.Redirect(301, "/api/permissions") |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,61 +1,60 @@ | |||||||
| package config | package config | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strconv" | 
 | ||||||
|  | 	"github.com/go-redis/redis/v8" | ||||||
|  | 	"gorm.io/driver/mysql" | ||||||
|  | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type DBConfig struct { |  | ||||||
| 	Host     string |  | ||||||
| 	Port     int |  | ||||||
| 	User     string |  | ||||||
| 	Password string |  | ||||||
| 	Name     string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (db *DBConfig) DSN() string { |  | ||||||
| 	return db.User + ":" + db.Password + "@tcp(" + db.Host + ":" + strconv.Itoa(db.Port) + ")/" + db.Name + "?charset=utf8mb4&parseTime=True&loc=Local" |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Config struct { | type Config struct { | ||||||
| 	DB            DBConfig | 	DBHost     string | ||||||
| 	JWTSecret     string | 	DBPort     string | ||||||
| 	RedisHost     string | 	DBUser     string | ||||||
| 	RedisPort     int | 	DBPassword string | ||||||
| 	RedisPassword string | 	DBName     string | ||||||
|  | 	RedisAddr  string | ||||||
|  | 	RedisPass  string | ||||||
| 	RedisDB    int | 	RedisDB    int | ||||||
|  | 	ServerPort string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var AppConfig Config | func LoadConfig() *Config { | ||||||
| 
 | 	return &Config{ | ||||||
| func Init() { | 		DBHost:     os.Getenv("DB_HOST"), | ||||||
| 	AppConfig = Config{ | 		DBPort:     os.Getenv("DB_PORT"), | ||||||
| 		DB: DBConfig{ | 		DBUser:     os.Getenv("DB_USER"), | ||||||
| 			Host:     getEnv("DB_HOST", "192.168.65.5"), | 		DBPassword: os.Getenv("DB_PASSWORD"), | ||||||
| 			Port:     getEnvAsInt("DB_PORT", 3306), | 		DBName:     os.Getenv("DB_NAME"), | ||||||
| 			User:     getEnv("DB_USER", "root"), | 		RedisAddr:  os.Getenv("REDIS_ADDR"), | ||||||
| 			Password: getEnv("DB_PASSWORD", "d8db*#00oS"), | 		RedisPass:  os.Getenv("REDIS_PASS"), | ||||||
| 			Name:     getEnv("DB_NAME", "rbac"), | 		RedisDB:    0, | ||||||
| 		}, | 		ServerPort: os.Getenv("SERVER_PORT"), | ||||||
| 		JWTSecret:     getEnv("JWT_SECRET", "secret"), |  | ||||||
| 		RedisHost:     getEnv("REDIS_HOST", "192.168.65.5"), |  | ||||||
| 		RedisPort:     getEnvAsInt("REDIS_PORT", 6379), |  | ||||||
| 		RedisPassword: getEnv("REDIS_PASSWORD", ""), |  | ||||||
| 		RedisDB:       getEnvAsInt("REDIS_DB", 2), |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getEnv(key, defaultValue string) string { | func InitDB(cfg *Config) *gorm.DB { | ||||||
| 	if value, exists := os.LookupEnv(key); exists { | 	dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", | ||||||
| 		return value | 		cfg.DBUser, cfg.DBPassword, cfg.DBHost, cfg.DBPort, cfg.DBName) | ||||||
|  | 	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to connect to database: %v", err) | ||||||
| 	} | 	} | ||||||
| 	return defaultValue | 	return db | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func getEnvAsInt(key string, defaultValue int) int { | func InitRedis(cfg *Config) *redis.Client { | ||||||
| 	valueStr := getEnv(key, "") | 	rdb := redis.NewClient(&redis.Options{ | ||||||
| 	if value, err := strconv.Atoi(valueStr); err == nil { | 		Addr:     cfg.RedisAddr, | ||||||
| 		return value | 		Password: cfg.RedisPass, | ||||||
|  | 		DB:       cfg.RedisDB, | ||||||
|  | 	}) | ||||||
|  | 	_, err := rdb.Ping(rdb.Context()).Result() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalf("Failed to connect to Redis: %v", err) | ||||||
| 	} | 	} | ||||||
| 	return defaultValue | 	return rdb | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,42 +1,104 @@ | |||||||
| package controllers | package controllers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/services" | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | 
 | ||||||
|  | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
|  | 	"gitea.zjmud.com/phyer/rbac/repositories" | ||||||
|  | 	"gitea.zjmud.com/phyer/rbac/utils" | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"github.com/go-redis/redis/v8" | ||||||
|  | 	"github.com/go-redis/redis/v8" | ||||||
|  | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Register(c *gin.Context) { | type AuthController struct { | ||||||
| 	var registerData struct { | 	DB    *gorm.DB | ||||||
| 		Username string `json:"username"` | 	Redis *redis.Client | ||||||
| 		Fullname string `json:"fullname"` |  | ||||||
| 		Password string `json:"password"` |  | ||||||
| 		Email    string `json:"email"` |  | ||||||
| 	} |  | ||||||
| 	if err := c.ShouldBindJSON(®isterData); err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	user, err := services.RegisterUser(registerData.Username, registerData.Fullname, registerData.Password, registerData.Email) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(201, user) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func Login(c *gin.Context) { | func NewAuthController(db *gorm.DB, redis *redis.Client) *AuthController { | ||||||
| 	var loginData struct { | 	return &AuthController{DB: db, Redis: redis} | ||||||
| 		Username string `json:"username"` | } | ||||||
| 		Password string `json:"password"` | 
 | ||||||
| 	} | func (ac *AuthController) Login(c *gin.Context) { | ||||||
| 	if err := c.ShouldBindJSON(&loginData); err != nil { | 	type LoginRequest struct { | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) | 		Username string `json:"username" binding:"required"` | ||||||
| 		return | 		Password string `json:"password" binding:"required"` | ||||||
| 	} | 	} | ||||||
| 	token, err := services.Login(loginData.Username, loginData.Password) | 
 | ||||||
| 	if err != nil { | 	var req LoginRequest | ||||||
| 		c.JSON(401, gin.H{"error": err.Error()}) | 	if err := c.ShouldBindJSON(&req); err != nil { | ||||||
| 		return | 		utils.Error(c, http.StatusBadRequest, "Invalid request format") | ||||||
| 	} | 		return | ||||||
| 	c.JSON(200, gin.H{"token": token}) | 	} | ||||||
|  | 
 | ||||||
|  | 	userRepo := repositories.NewUserRepository(ac.DB) | ||||||
|  | 	user, err := userRepo.FindByUsername(req.Username) | ||||||
|  | 	if err != nil { | ||||||
|  | 		utils.Error(c, http.StatusUnauthorized, "Invalid credentials") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	hashedPassword, err := models.HashPassword(req.Password) | ||||||
|  | 	if err != nil { | ||||||
|  | 		utils.Error(c, http.StatusUnauthorized, "Invalid credentials") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	hashedHex := fmt.Sprintf("%x", hashedPassword) | ||||||
|  | 	if hashedHex != user.Password { | ||||||
|  | 	if err != nil { | ||||||
|  | 		utils.Error(c, http.StatusUnauthorized, "Invalid credentials") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	hashedHex := fmt.Sprintf("%x", hashedPassword) | ||||||
|  | 	if hashedHex != user.Password { | ||||||
|  | 		utils.Error(c, http.StatusUnauthorized, "Invalid credentials") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	token, err := utils.GenerateToken(user.ID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		utils.Error(c, http.StatusInternalServerError, "Failed to generate token") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	utils.Success(c, gin.H{"token": token}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (ac *AuthController) Register(c *gin.Context) { | ||||||
|  | 	type RegisterRequest struct { | ||||||
|  | 		Username string `json:"username" binding:"required"` | ||||||
|  | 		Password string `json:"password" binding:"required"` | ||||||
|  | 		Email    string `json:"email" binding:"required,email"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var req RegisterRequest | ||||||
|  | 	if err := c.ShouldBindJSON(&req); err != nil { | ||||||
|  | 		utils.Error(c, http.StatusBadRequest, "Invalid request format") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hashedPassword, err := models.HashPassword(req.Password) | ||||||
|  | 	if err != nil { | ||||||
|  | 		utils.Error(c, http.StatusInternalServerError, "Failed to hash password") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	newUser := &models.User{ | ||||||
|  | 		Username: req.Username, | ||||||
|  | 		Password: string(hashedPassword), | ||||||
|  | 		Email:    req.Email, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	userRepo := repositories.NewUserRepository(ac.DB) | ||||||
|  | 	if err := userRepo.Create(newUser); err != nil { | ||||||
|  | 		utils.Error(c, http.StatusConflict, "User already exists") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	utils.Success(c, newUser) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,228 +1,53 @@ | |||||||
| package controllers | package controllers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	// "log" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"strconv" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 
 |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/services" |  | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| 	"github.com/sirupsen/logrus" | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // CreateRole 创建新角色 | type RBACController struct { | ||||||
| func CreateRole(c *gin.Context) { | 	DB    *gorm.DB | ||||||
| 	var roleData struct { | 	Redis *redis.Client | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewRBACController(db *gorm.DB, redis *redis.Client) *RBACController { | ||||||
|  | 	return &RBACController{DB: db, Redis: redis} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (rc *RBACController) CreateRole(c *gin.Context) { | ||||||
|  | 	type CreateRoleRequest struct { | ||||||
| 		Name        string `json:"name" binding:"required"` | 		Name        string `json:"name" binding:"required"` | ||||||
| 		Description string `json:"description"` | 		Description string `json:"description"` | ||||||
| 	} | 	} | ||||||
| 	if err := c.ShouldBindJSON(&roleData); err != nil { | 
 | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) | 	var req CreateRoleRequest | ||||||
|  | 	if err := c.ShouldBindJSON(&req); err != nil { | ||||||
|  | 		utils.Error(c, http.StatusBadRequest, "Invalid request format") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	role, err := services.CreateRole(roleData.Name, roleData.Description) | 	// 检查角色是否已存在 | ||||||
| 	if err != nil { | 	roleRepo := repositories.NewRoleRepository(rc.DB) | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) | 	exists, err := roleRepo.ExistsByNameExcludeID(req.Name, 0) | ||||||
|  | 	if err != nil || exists { | ||||||
|  | 		utils.Error(c, http.StatusConflict, "Role already exists") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	c.JSON(201, role) | 
 | ||||||
|  | 	newRole := &models.Role{ | ||||||
|  | 		Name:        req.Name, | ||||||
|  | 		Description: req.Description, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := roleRepo.Create(newRole); err != nil { | ||||||
|  | 		utils.Error(c, http.StatusInternalServerError, "Failed to create role") | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	utils.Success(c, newRole) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GetRoles 获取所有角色 | // 其他RBAC相关方法... | ||||||
| func GetRoles(c *gin.Context) { |  | ||||||
| 	roles, err := services.GetAllRoles() |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, roles) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CreatePermission 创建新权限 |  | ||||||
| func CreatePermission(c *gin.Context) { |  | ||||||
| 	logrus.Info("CreatePermission called") |  | ||||||
| 
 |  | ||||||
| 	var permissionData struct { |  | ||||||
| 		Name        string `json:"name" binding:"required"` |  | ||||||
| 		Description string `json:"description"` |  | ||||||
| 		Resource    string `json:"resource" binding:"required"` |  | ||||||
| 		Action      string `json:"action" binding:"required"` |  | ||||||
| 	} |  | ||||||
| 	if err := c.ShouldBindJSON(&permissionData); err != nil { |  | ||||||
| 		logrus.Errorf("Error binding JSON: %v", err) |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	permission, err := services.CreatePermission(permissionData.Name, permissionData.Description, permissionData.Resource, permissionData.Action) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logrus.Errorf("Error creating permission: %v", err) |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	logrus.Infof("Permission created: %+v", permission) |  | ||||||
| 	c.JSON(201, permission) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // AssignRoleToUser 为用户分配角色 |  | ||||||
| func AssignRoleToUser(c *gin.Context) { |  | ||||||
| 	var assignmentData struct { |  | ||||||
| 		UserID uint `json:"user_id" binding:"required"` |  | ||||||
| 		RoleID uint `json:"role_id" binding:"required"` |  | ||||||
| 	} |  | ||||||
| 	if err := c.ShouldBindJSON(&assignmentData); err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err := services.AssignRoleToUser(assignmentData.UserID, assignmentData.RoleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, gin.H{"message": "Role assigned successfully"}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // AssignPermissionToRole 为角色分配权限 |  | ||||||
| func AssignPermissionToRole(c *gin.Context) { |  | ||||||
| 	var assignmentData struct { |  | ||||||
| 		RoleID       uint `json:"role_id" binding:"required"` |  | ||||||
| 		PermissionID uint `json:"permission_id" binding:"required"` |  | ||||||
| 	} |  | ||||||
| 	if err := c.ShouldBindJSON(&assignmentData); err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err := services.AssignPermissionToRole(assignmentData.RoleID, assignmentData.PermissionID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, gin.H{"message": "Permission assigned successfully"}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetPermission 获取单个权限 |  | ||||||
| func GetPermission(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	permissionID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid permission ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	permission, err := services.GetPermissionByID(uint(permissionID)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, permission) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UpdatePermission 更新权限 |  | ||||||
| func UpdatePermission(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	permissionID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid permission ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	var updateData map[string]interface{} |  | ||||||
| 	if err := c.ShouldBindJSON(&updateData); err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	permission, err := services.UpdatePermission(uint(permissionID), updateData) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, permission) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeletePermission 删除权限 |  | ||||||
| func DeletePermission(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	permissionID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid permission ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = services.DeletePermission(uint(permissionID)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, gin.H{"message": "Permission deleted successfully"}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetPermissions 获取所有权限 |  | ||||||
| func GetPermissions(c *gin.Context) { |  | ||||||
| 	permissions, err := services.GetAllPermissions() |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, permissions) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetRole 获取单个角色 |  | ||||||
| func GetRole(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	roleID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid role ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	role, err := services.GetRoleByID(uint(roleID)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, role) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UpdateRole 更新角色 |  | ||||||
| func UpdateRole(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	roleID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid role ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	var updateData map[string]interface{} |  | ||||||
| 	if err := c.ShouldBindJSON(&updateData); err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	role, err := services.UpdateRole(uint(roleID), updateData) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, role) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeleteRole 删除角色 |  | ||||||
| func DeleteRole(c *gin.Context) { |  | ||||||
| 	id := c.Param("id") |  | ||||||
| 	roleID, err := strconv.ParseUint(id, 10, 64) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(400, gin.H{"error": "Invalid role ID"}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = services.DeleteRole(uint(roleID)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, gin.H{"message": "Role deleted successfully"}) |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,50 +1,37 @@ | |||||||
| package controllers | package controllers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/services" | 	"net/http" | ||||||
|  | 
 | ||||||
|  | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func GetUsers(c *gin.Context) { | type UserController struct { | ||||||
| 	users, err := services.GetAllUsers() | 	DB    *gorm.DB | ||||||
| 	if err != nil { | 	Redis *redis.Client | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, users) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUser(c *gin.Context) { | func NewUserController(db *gorm.DB, redis *redis.Client) *UserController { | ||||||
| 	id := c.Param("id") | 	return &UserController{DB: db, Redis: redis} | ||||||
| 	user, err := services.GetUserByID(id) |  | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, user) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func UpdateUser(c *gin.Context) { | func (uc *UserController) GetUsers(c *gin.Context) { | ||||||
| 	id := c.Param("id") | 	var users []models.User | ||||||
| 	var updateData map[string]interface{} | 	if err := uc.DB.Find(&users).Error; err != nil { | ||||||
| 	if err := c.ShouldBindJSON(&updateData); err != nil { | 		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch users"}) | ||||||
| 		c.JSON(400, gin.H{"error": err.Error()}) |  | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	user, err := services.UpdateUser(id, updateData) | 	c.JSON(http.StatusOK, users) | ||||||
| 	if err != nil { |  | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	c.JSON(200, user) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func DeleteUser(c *gin.Context) { | func (uc *UserController) GetUserByID(c *gin.Context) { | ||||||
| 	id := c.Param("id") | 	id := c.Param("id") | ||||||
| 	err := services.DeleteUser(id) | 	var user models.User | ||||||
| 	if err != nil { | 	if err := uc.DB.First(&user, id).Error; err != nil { | ||||||
| 		c.JSON(500, gin.H{"error": err.Error()}) | 		c.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	c.JSON(200, gin.H{"message": "User deleted successfully"}) | 	c.JSON(http.StatusOK, user) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,17 +1,17 @@ | |||||||
| module gitea.zjmud.xyz/phyer/rbac | module gitea.zjmud.com/phyer/rbac | ||||||
| 
 | 
 | ||||||
| go 1.21 | go 1.20 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/gin-gonic/gin v1.9.1 | 	github.com/gin-gonic/gin v1.9.1 | ||||||
| 	github.com/go-redis/redis/v8 v8.11.5 | 	github.com/go-redis/redis/v8 v8.11.5 // 使用存在的版本 | ||||||
| 	github.com/golang-jwt/jwt/v5 v5.0.0 | 	github.com/go-sql-driver/mysql v1.7.1 // indirect | ||||||
| 	github.com/sirupsen/logrus v1.9.3 | 	gorm.io/driver/mysql v1.5.1 | ||||||
| 	golang.org/x/crypto v0.9.0 | 	gorm.io/gorm v1.25.4 | ||||||
| 	gorm.io/driver/mysql v1.5.7 |  | ||||||
| 	gorm.io/gorm v1.25.7 |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | require github.com/golang-jwt/jwt/v5 v5.2.1 | ||||||
|  | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/bytedance/sonic v1.9.1 // indirect | 	github.com/bytedance/sonic v1.9.1 // indirect | ||||||
| 	github.com/cespare/xxhash/v2 v2.1.2 // indirect | 	github.com/cespare/xxhash/v2 v2.1.2 // indirect | ||||||
| @ -22,7 +22,6 @@ require ( | |||||||
| 	github.com/go-playground/locales v0.14.1 // indirect | 	github.com/go-playground/locales v0.14.1 // indirect | ||||||
| 	github.com/go-playground/universal-translator v0.18.1 // indirect | 	github.com/go-playground/universal-translator v0.18.1 // indirect | ||||||
| 	github.com/go-playground/validator/v10 v10.14.0 // indirect | 	github.com/go-playground/validator/v10 v10.14.0 // indirect | ||||||
| 	github.com/go-sql-driver/mysql v1.7.0 // indirect |  | ||||||
| 	github.com/goccy/go-json v0.10.2 // indirect | 	github.com/goccy/go-json v0.10.2 // indirect | ||||||
| 	github.com/jinzhu/inflection v1.0.0 // indirect | 	github.com/jinzhu/inflection v1.0.0 // indirect | ||||||
| 	github.com/jinzhu/now v1.1.5 // indirect | 	github.com/jinzhu/now v1.1.5 // indirect | ||||||
| @ -36,6 +35,7 @@ require ( | |||||||
| 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | ||||||
| 	github.com/ugorji/go/codec v1.2.11 // indirect | 	github.com/ugorji/go/codec v1.2.11 // indirect | ||||||
| 	golang.org/x/arch v0.3.0 // indirect | 	golang.org/x/arch v0.3.0 // indirect | ||||||
|  | 	golang.org/x/crypto v0.9.0 // indirect | ||||||
| 	golang.org/x/net v0.10.0 // indirect | 	golang.org/x/net v0.10.0 // indirect | ||||||
| 	golang.org/x/sys v0.8.0 // indirect | 	golang.org/x/sys v0.8.0 // indirect | ||||||
| 	golang.org/x/text v0.9.0 // indirect | 	golang.org/x/text v0.9.0 // indirect | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								go.sum
									
									
									
									
									
								
							| @ -12,7 +12,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs | |||||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||||||
| github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | ||||||
| github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= |  | ||||||
| github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= | ||||||
| github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= | ||||||
| github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | ||||||
| @ -20,7 +19,6 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm | |||||||
| github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= | ||||||
| github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= | ||||||
| github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= | ||||||
| github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= |  | ||||||
| github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= | ||||||
| github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= | ||||||
| github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | ||||||
| @ -29,12 +27,13 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg | |||||||
| github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= | ||||||
| github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= | github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= | ||||||
| github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= | github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= | ||||||
| github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= |  | ||||||
| github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= | ||||||
|  | github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= | ||||||
|  | github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= | ||||||
| github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | ||||||
| github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | ||||||
| github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= | github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= | ||||||
| github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= | github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= | ||||||
| github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||||||
| github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | ||||||
| github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
| @ -58,17 +57,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ | |||||||
| github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | ||||||
| github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | ||||||
| github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= | ||||||
| github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= |  | ||||||
| github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= | ||||||
| github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= |  | ||||||
| github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= | github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= | ||||||
| github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= |  | ||||||
| github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= | ||||||
| github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= |  | ||||||
| github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= |  | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||||
| github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||||||
| @ -92,7 +86,6 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 | |||||||
| golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= | ||||||
| golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | ||||||
| golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |  | ||||||
| golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= | ||||||
| golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| @ -106,14 +99,13 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw | |||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | ||||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |  | ||||||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |  | ||||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
| gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= | gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= | ||||||
| gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= | gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= | ||||||
| gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= | gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= | ||||||
| gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= | gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= | ||||||
|  | gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= | ||||||
| rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= | ||||||
|  | |||||||
							
								
								
									
										32
									
								
								init.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								init.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,32 @@ | |||||||
|  | # 创建所有目录 | ||||||
|  | mkdir -p api config controllers middleware models repositories server services utils | ||||||
|  | 
 | ||||||
|  | # 创建api目录下的文件 | ||||||
|  | touch api/routes.go | ||||||
|  | 
 | ||||||
|  | # 创建config目录下的文件 | ||||||
|  | touch config/config.go | ||||||
|  | 
 | ||||||
|  | # 创建controllers目录下的文件 | ||||||
|  | touch controllers/auth.go controllers/rbac.go controllers/user.go | ||||||
|  | 
 | ||||||
|  | # 创建middleware目录下的文件 | ||||||
|  | touch middleware/auth.go middleware/rbac.go | ||||||
|  | 
 | ||||||
|  | # 创建models目录下的文件 | ||||||
|  | touch models/permission.go models/role.go models/user.go models/user_group.go | ||||||
|  | 
 | ||||||
|  | # 创建repositories目录下的文件 | ||||||
|  | touch repositories/db.go repositories/permission.go repositories/role.go repositories/user.go repositories/user_group.go | ||||||
|  | 
 | ||||||
|  | # 创建server目录下的文件 | ||||||
|  | touch server/server.go | ||||||
|  | 
 | ||||||
|  | # 创建services目录下的文件 | ||||||
|  | touch services/auth.go services/rbac.go services/user.go | ||||||
|  | 
 | ||||||
|  | # 创建utils目录下的文件 | ||||||
|  | touch utils/jwt.go utils/redis.go utils/response.go | ||||||
|  | 
 | ||||||
|  | # 创建其他文件 | ||||||
|  | touch go.mod go.sum main.go sug.md tree.txt rbac/ | ||||||
							
								
								
									
										30
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								main.go
									
									
									
									
									
								
							| @ -1,18 +1,28 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/api" | 	"log" | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/config" | 
 | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/repositories" | 	"gitea.zjmud.com/phyer/rbac/api" | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/server" | 	"gitea.zjmud.com/phyer/rbac/config" | ||||||
|  | 	"github.com/gin-gonic/gin" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	config.Init() | 	// 加载配置 | ||||||
| 	if err := repositories.InitDB(); err != nil { | 	cfg := config.LoadConfig() | ||||||
| 		panic("failed to initialize database: " + err.Error()) | 
 | ||||||
|  | 	// 初始化数据库 | ||||||
|  | 	db := config.InitDB(cfg) | ||||||
|  | 
 | ||||||
|  | 	// 初始化Redis | ||||||
|  | 	redisClient := config.InitRedis(cfg) | ||||||
|  | 
 | ||||||
|  | 	// 初始化路由 | ||||||
|  | 	router := api.SetupRouter(db, redisClient) | ||||||
|  | 
 | ||||||
|  | 	// 启动服务 | ||||||
|  | 	if err := router.Run(":" + cfg.ServerPort); err != nil { | ||||||
|  | 		log.Fatalf("Failed to start server: %v", err) | ||||||
| 	} | 	} | ||||||
| 	r := server.NewServer() |  | ||||||
| 	api.SetupRoutes(r) |  | ||||||
| 	r.Run(":8080") |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,31 +1,27 @@ | |||||||
| package middleware | package middlewares | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/utils" |  | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // JWTAuth is an alias for AuthMiddleware |  | ||||||
| func JWTAuth() gin.HandlerFunc { |  | ||||||
| 	return AuthMiddleware() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func AuthMiddleware() gin.HandlerFunc { | func AuthMiddleware() gin.HandlerFunc { | ||||||
| 	return func(c *gin.Context) { | 	return func(c *gin.Context) { | ||||||
| 		token := c.GetHeader("Authorization") | 		tokenString := c.GetHeader("Authorization") | ||||||
| 		if token == "" { | 		if tokenString == "" { | ||||||
| 			c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"}) | 			utils.Error(c, http.StatusUnauthorized, "Authorization header required") | ||||||
|  | 			c.Abort() | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		claims, err := utils.ParseJWT(token) | 		claims, err := utils.ParseToken(tokenString) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"}) | 			utils.Error(c, http.StatusUnauthorized, "Invalid token") | ||||||
|  | 			c.Abort() | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		userID := claims["user_id"].(string) | 		c.Set("userID", claims.UserID) | ||||||
| 		c.Set("userID", userID) |  | ||||||
| 		c.Next() | 		c.Next() | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,23 +1,31 @@ | |||||||
| package middleware | package middlewares | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/repositories" |  | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
|  | 	"net/http" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func RBACMiddleware(permission string) gin.HandlerFunc { | func RBACMiddleware() gin.HandlerFunc { | ||||||
| 	return func(c *gin.Context) { | 	return func(c *gin.Context) { | ||||||
| 		userID := c.GetString("userID") | 		// 获取用户ID | ||||||
| 		if userID == "" { | 		userID, exists := c.Get("userID") | ||||||
| 			c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"}) | 		if !exists { | ||||||
|  | 			utils.Error(c, http.StatusForbidden, "User authentication required") | ||||||
|  | 			c.Abort() | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		hasPermission, err := repositories.CheckUserPermission(userID, permission) | 		// 获取请求方法和路径 | ||||||
| 		if err != nil || !hasPermission { | 		method := c.Request.Method | ||||||
| 			c.AbortWithStatusJSON(403, gin.H{"error": "Forbidden"}) | 		path := c.FullPath() | ||||||
| 			return | 
 | ||||||
| 		} | 		// 这里需要实现RBAC检查逻辑(示例代码) | ||||||
|  | 		// 实际应该查询用户的角色权限是否匹配当前请求 | ||||||
|  | 		// if !checkPermission(userID, method, path) { | ||||||
|  | 		//     utils.Error(c, http.StatusForbidden, "Access denied") | ||||||
|  | 		//     c.Abort() | ||||||
|  | 		//     return | ||||||
|  | 		// } | ||||||
| 
 | 
 | ||||||
| 		c.Next() | 		c.Next() | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -1,11 +1,16 @@ | |||||||
| package models | package models | ||||||
| 
 | 
 | ||||||
| import "gorm.io/gorm" | import "time" | ||||||
| 
 | 
 | ||||||
| type Permission struct { | type Permission struct { | ||||||
| 	gorm.Model | 	ID          uint      `gorm:"primaryKey" json:"id"` | ||||||
| 	Name        string `gorm:"unique;not null"` | 	Name        string    `gorm:"uniqueIndex;size:50" json:"name"` | ||||||
| 	Description string | 	Description string    `gorm:"size:255" json:"description"` | ||||||
| 	Resource    string `gorm:"not null"` | 	ResourceID  uint      `json:"resource_id"` | ||||||
| 	Action      string `gorm:"not null"` | 	ActionID    uint      `json:"action_id"` | ||||||
|  | 	CreatedAt   time.Time `json:"created_at"` | ||||||
|  | 	UpdatedAt   time.Time `json:"updated_at"` | ||||||
|  | 
 | ||||||
|  | 	Resource Resource `gorm:"foreignKey:ResourceID"` | ||||||
|  | 	Action   Action   `gorm:"foreignKey:ActionID"` | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| package models | package models | ||||||
| 
 | 
 | ||||||
| import "gorm.io/gorm" | import "time" | ||||||
| 
 | 
 | ||||||
| type Role struct { | type Role struct { | ||||||
| 	gorm.Model | 	ID          uint      `gorm:"primaryKey" json:"id"` | ||||||
| 	Name        string       `gorm:"unique;not null"` | 	Name        string    `gorm:"uniqueIndex;size:50" json:"name"` | ||||||
| 	Permissions []Permission `gorm:"many2many:role_permissions;"` | 	Description string    `gorm:"size:255" json:"description"` | ||||||
|  | 	CreatedAt   time.Time `json:"created_at"` | ||||||
|  | 	UpdatedAt   time.Time `json:"updated_at"` | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,18 +1,35 @@ | |||||||
| package models | package models | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	// "crypto/rand" | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
| 	"time" | 	"time" | ||||||
| 
 |  | ||||||
| 	"gorm.io/gorm" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type User struct { | type User struct { | ||||||
| 	gorm.Model | 	ID        uint      `gorm:"primaryKey" json:"id"` | ||||||
| 	Username  string    `json:"username" gorm:"uniqueIndex;not null"` | 	Username  string    `gorm:"uniqueIndex;size:50" json:"username"` | ||||||
| 	Fullname  string    `json:"fullname" gorm:"not null"` | 	Email     string    `gorm:"uniqueIndex;size:100" json:"email"` | ||||||
| 	Password  string    `json:"-" gorm:"not null"` | 	Password  string    `gorm:"size:255" json:"-"` | ||||||
| 	Email     string    `json:"email" gorm:"uniqueIndex;not null"` |  | ||||||
| 	CreatedAt time.Time `json:"created_at"` | 	CreatedAt time.Time `json:"created_at"` | ||||||
| 	UpdatedAt time.Time `json:"updated_at"` | 	UpdatedAt time.Time `json:"updated_at"` | ||||||
| 	Roles     []Role    `json:"roles" gorm:"many2many:user_roles;"` | } | ||||||
|  | 
 | ||||||
|  | // HashPassword 迁移到 utils 包更合适(可选) | ||||||
|  | func HashPassword(password string) ([]byte, error) { | ||||||
|  | 	h := sha256.New() | ||||||
|  | 	if _, err := io.WriteString(h, password); err != nil { // 修正[]byte转换 | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return h.Sum(nil), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Validate 建议移动到 service 层(可选) | ||||||
|  | func (u *User) Validate() error { | ||||||
|  | 	if u.Password == "" { | ||||||
|  | 		return fmt.Errorf("password cannot be empty") | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,18 +1,11 @@ | |||||||
| package models | package models | ||||||
| 
 | 
 | ||||||
| import ( | import "time" | ||||||
| 	"time" |  | ||||||
| 
 | 
 | ||||||
| 	"gorm.io/gorm" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // UserGroup 表示用户组模型 |  | ||||||
| type UserGroup struct { | type UserGroup struct { | ||||||
| 	gorm.Model | 	ID          uint      `gorm:"primaryKey" json:"id"` | ||||||
| 	Name        string    `json:"name" gorm:"uniqueIndex;not null"`         // 用户组名称 | 	Name        string    `gorm:"uniqueIndex;size:50" json:"name"` | ||||||
| 	Description string    `json:"description"`                              // 用户组描述 | 	Description string    `gorm:"size:255" json:"description"` | ||||||
| 	CreatedAt   time.Time `json:"created_at"`                               // 创建时间 | 	CreatedAt   time.Time `json:"created_at"` | ||||||
| 	UpdatedAt   time.Time `json:"updated_at"`                               // 更新时间 | 	UpdatedAt   time.Time `json:"updated_at"` | ||||||
| 	Users       []User    `json:"users" gorm:"many2many:user_group_users;"` // 关联的用户 |  | ||||||
| 	Roles       []Role    `json:"roles" gorm:"many2many:user_group_roles;"` // 关联的角色 |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										6
									
								
								models/user_role.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								models/user_role.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | type UserRole struct { | ||||||
|  | 	UserID uint `gorm:"primaryKey" json:"user_id"` | ||||||
|  | 	RoleID uint `gorm:"primaryKey" json:"role_id"` | ||||||
|  | } | ||||||
| @ -1,21 +1,53 @@ | |||||||
| package repositories | package repositories | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/config" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" |  | ||||||
| 	"gorm.io/driver/mysql" |  | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| 	// "strconv" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var db *gorm.DB | // BaseRepository 提供基础CRUD操作 | ||||||
| 
 | type BaseRepository struct { | ||||||
| func InitDB() error { | 	db *gorm.DB | ||||||
| 	var err error | } | ||||||
| 	dsn := config.AppConfig.DB.DSN() | 
 | ||||||
| 	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) | func NewBaseRepository(db *gorm.DB) *BaseRepository { | ||||||
| 	if err != nil { | 	return &BaseRepository{db: db} | ||||||
| 		return err | } | ||||||
| 	} | 
 | ||||||
| 	return db.AutoMigrate(&models.Permission{}, &models.Role{}, &models.UserGroup{}, &models.User{}) | // 事务支持 | ||||||
|  | func (r *BaseRepository) Begin() *gorm.DB { | ||||||
|  | 	return r.db.Begin() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) Commit(tx *gorm.DB) error { | ||||||
|  | 	return tx.Commit().Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) Rollback(tx *gorm.DB) error { | ||||||
|  | 	return tx.Rollback().Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 基础CRUD操作 | ||||||
|  | func (r *BaseRepository) Create(model interface{}) error { | ||||||
|  | 	return r.db.Create(model).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) Update(model interface{}) error { | ||||||
|  | 	return r.db.Save(model).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) Delete(model interface{}) error { | ||||||
|  | 	return r.db.Delete(model).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) FindByID(model interface{}, id uint) error { | ||||||
|  | 	return r.db.First(model, id).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *BaseRepository) FindAll(models interface{}, preloads ...string) error { | ||||||
|  | 	tx := r.db | ||||||
|  | 	for _, preload := range preloads { | ||||||
|  | 		tx = tx.Preload(preload) | ||||||
|  | 	} | ||||||
|  | 	return tx.Find(models).Error | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,55 +1,55 @@ | |||||||
| package repositories | package repositories | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func GetPermissionByID(id uint) (*models.Permission, error) { | type PermissionRepository interface { | ||||||
| 	var permission models.Permission | 	Create(permission *models.Permission) error | ||||||
| 	result := db.First(&permission, id) | 	Update(permission *models.Permission) error | ||||||
| 	return &permission, result.Error | 	Delete(permission *models.Permission) error | ||||||
|  | 	FindByID(id uint) (*models.Permission, error) | ||||||
|  | 	FindAll() ([]models.Permission, error) | ||||||
|  | 	FindByName(name string) (*models.Permission, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetPermissions() ([]models.Permission, error) { | type permissionRepository struct { | ||||||
| 	var permissions []models.Permission | 	*BaseRepository | ||||||
| 	result := db.Find(&permissions) |  | ||||||
| 	return permissions, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func UpdatePermission(id uint, updateData map[string]interface{}) (*models.Permission, error) { | func NewPermissionRepository(db *gorm.DB) PermissionRepository { | ||||||
| 	var permission models.Permission | 	return &permissionRepository{ | ||||||
| 	result := db.Model(&permission).Where("id = ?", id).Updates(updateData) | 		BaseRepository: NewBaseRepository(db), | ||||||
| 	if result.Error != nil { |  | ||||||
| 		return nil, result.Error |  | ||||||
| 	} | 	} | ||||||
| 	return GetPermissionByID(id) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func CreatePermission(permission *models.Permission) (*models.Permission, error) { | func (r *permissionRepository) Create(permission *models.Permission) error { | ||||||
| 	result := db.Create(permission) | 	return r.BaseRepository.Create(permission) | ||||||
| 	return permission, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func DeletePermission(id uint) error { | func (r *permissionRepository) Update(permission *models.Permission) error { | ||||||
| 	result := db.Delete(&models.Permission{}, id) | 	return r.BaseRepository.Update(permission) | ||||||
| 	return result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func CheckPermissionExists(name string) (bool, error) { | func (r *permissionRepository) Delete(permission *models.Permission) error { | ||||||
| 	var count int64 | 	return r.BaseRepository.Delete(permission) | ||||||
| 	result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count) |  | ||||||
| 	return count > 0, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func AssignRoleToUser(userID uint, roleID uint) error { | func (r *permissionRepository) FindByID(id uint) (*models.Permission, error) { | ||||||
| 	user := &models.User{Model: gorm.Model{ID: userID}} | 	var permission models.Permission | ||||||
| 	role := &models.Role{Model: gorm.Model{ID: roleID}} | 	err := r.BaseRepository.FindByID(&permission, id) | ||||||
| 	return db.Model(user).Association("Roles").Append(role) | 	return &permission, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func RemoveRoleFromUser(userID uint, roleID uint) error { | func (r *permissionRepository) FindAll() ([]models.Permission, error) { | ||||||
| 	user := &models.User{Model: gorm.Model{ID: userID}} | 	var permissions []models.Permission | ||||||
| 	role := &models.Role{Model: gorm.Model{ID: roleID}} | 	err := r.BaseRepository.FindAll(&permissions) | ||||||
| 	return db.Model(user).Association("Roles").Delete(role) | 	return permissions, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *permissionRepository) FindByName(name string) (*models.Permission, error) { | ||||||
|  | 	var permission models.Permission | ||||||
|  | 	err := r.db.Where("name = ?", name).First(&permission).Error | ||||||
|  | 	return &permission, err | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,59 +1,53 @@ | |||||||
| package repositories | package repositories | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CreateRole(role *models.Role) (*models.Role, error) { | type RoleRepository struct { | ||||||
| 	result := db.Create(role) | 	*BaseRepository | ||||||
| 	return role, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetAllRoles() ([]models.Role, error) { | func NewRoleRepository(db *gorm.DB) *RoleRepository { | ||||||
| 	var roles []models.Role | 	return &RoleRepository{ | ||||||
| 	result := db.Find(&roles) | 		BaseRepository: NewBaseRepository(db), | ||||||
| 	return roles, result.Error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func GetRoleByID(id uint) (*models.Role, error) { |  | ||||||
| 	var role models.Role |  | ||||||
| 	result := db.First(&role, id) |  | ||||||
| 	return &role, result.Error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func CheckRoleExists(name string) (bool, error) { |  | ||||||
| 	var count int64 |  | ||||||
| 	result := db.Model(&models.Role{}).Where("name = ?", name).Count(&count) |  | ||||||
| 	return count > 0, result.Error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func AddPermissionToRole(roleID, permissionID uint) error { |  | ||||||
| 	role := &models.Role{Model: gorm.Model{ID: roleID}} |  | ||||||
| 	permission := &models.Permission{Model: gorm.Model{ID: permissionID}} |  | ||||||
| 	return db.Model(role).Association("Permissions").Append(permission) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func GetRoles() ([]models.Role, error) { |  | ||||||
| 	var roles []models.Role |  | ||||||
| 	result := db.Preload("Permissions").Find(&roles) |  | ||||||
| 	return roles, result.Error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func UpdateRole(id uint, updateData map[string]interface{}) (*models.Role, error) { |  | ||||||
| 	var role models.Role |  | ||||||
| 	result := db.Model(&role).Where("id = ?", id).Updates(updateData) |  | ||||||
| 	if result.Error != nil { |  | ||||||
| 		return nil, result.Error |  | ||||||
| 	} | 	} | ||||||
| 	return GetRoleByID(id) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func DeleteRole(id uint) error { | // 根据角色名称查找角色 | ||||||
| 	result := db.Delete(&models.Role{}, id) | func (r *RoleRepository) FindByName(role *models.Role, name string) error { | ||||||
| 	return result.Error | 	return r.db.Where("name = ?", name).First(role).Error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func RemovePermissionFromRole(roleID uint, permissionID uint) error { | // 分页查询角色列表 | ||||||
| 	return db.Model(&models.Role{Model: gorm.Model{ID: roleID}}).Association("Permissions").Delete(&models.Permission{Model: gorm.Model{ID: permissionID}}) | func (r *RoleRepository) FindPaged(roles *[]models.Role, page, pageSize int, preloads ...string) error { | ||||||
|  | 	tx := r.db.Model(&models.Role{}) | ||||||
|  | 
 | ||||||
|  | 	for _, preload := range preloads { | ||||||
|  | 		tx = tx.Preload(preload) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return tx.Scopes(func(db *gorm.DB) *gorm.DB { | ||||||
|  | 		return db.Offset((page - 1) * pageSize).Limit(pageSize) | ||||||
|  | 	}).Find(roles).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 带权限关联的角色查询 | ||||||
|  | func (r *RoleRepository) FindWithPermissions(role *models.Role, id uint) error { | ||||||
|  | 	return r.db.Preload("Permissions").First(role, id).Error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 检查角色名称是否存在(排除当前角色) | ||||||
|  | func (r *RoleRepository) ExistsByNameExcludeID(name string, excludeID uint) (bool, error) { | ||||||
|  | 	var count int64 | ||||||
|  | 	err := r.db.Model(&models.Role{}). | ||||||
|  | 		Where("name = ? AND id != ?", name, excludeID). | ||||||
|  | 		Count(&count).Error | ||||||
|  | 	return count > 0, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 同步角色权限关联 | ||||||
|  | func (r *RoleRepository) SyncPermissions(role *models.Role, permissionIDs []uint) error { | ||||||
|  | 	return r.db.Model(role).Association("Permissions").Replace(permissionIDs) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,60 +1,128 @@ | |||||||
| package repositories | package repositories | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	// "gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CheckUserPermission(userID string, permission string) (bool, error) { | type UserRepository interface { | ||||||
| 	var user models.User | 	Create(user *models.User) error | ||||||
| 	result := db.Preload("Roles.Permissions").Where("id = ?", userID).First(&user) | 	Update(user *models.User) error | ||||||
| 	if result.Error != nil { | 	Delete(user *models.User) error | ||||||
| 		return false, result.Error | 	FindByID(id uint) (*models.User, error) | ||||||
| 	} | 	FindAll() ([]models.User, error) | ||||||
| 
 | 	FindByUsername(username string) (*models.User, error) | ||||||
| 	for _, role := range user.Roles { |  | ||||||
| 		for _, perm := range role.Permissions { |  | ||||||
| 			if perm.Name == permission { |  | ||||||
| 				return true, nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false, nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetAllUsers() ([]models.User, error) { | type userRepository struct { | ||||||
|  | 	*BaseRepository | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NewUserRepository(db *gorm.DB) UserRepository { | ||||||
|  | 	return &userRepository{ | ||||||
|  | 		BaseRepository: NewBaseRepository(db), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) Create(user *models.User) error { | ||||||
|  | 	return r.BaseRepository.Create(user) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) Update(user *models.User) error { | ||||||
|  | 	return r.BaseRepository.Update(user) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) Delete(user *models.User) error { | ||||||
|  | 	return r.BaseRepository.Delete(user) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) FindByID(id uint) (*models.User, error) { | ||||||
|  | 	var user models.User | ||||||
|  | 	err := r.BaseRepository.FindByID(&user, id) | ||||||
|  | 	return &user, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) FindAll() ([]models.User, error) { | ||||||
| 	var users []models.User | 	var users []models.User | ||||||
| 	result := db.Find(&users) | 	err := r.BaseRepository.FindAll(&users) | ||||||
| 	return users, result.Error | 	return users, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUserByID(id string) (*models.User, error) { | func (r *userRepository) FindByUsername(username string) (*models.User, error) { | ||||||
| 	var user models.User | 	var user models.User | ||||||
| 	result := db.First(&user, "id = ?", id) | 	err := r.db.Where("username = ?", username).First(&user).Error | ||||||
| 	return &user, result.Error | 	return &user, err | ||||||
|  | } | ||||||
|  | package repositories | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
|  | 	"gorm.io/gorm" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type UserRepository interface { | ||||||
|  | 	Create(user *models.User) error | ||||||
|  | 	Update(user *models.User) error | ||||||
|  | 	Delete(user *models.User) error | ||||||
|  | 	FindByID(id uint) (*models.User, error) | ||||||
|  | 	FindAll() ([]models.User, error) | ||||||
|  | 	FindByUsername(username string) (*models.User, error) | ||||||
|  | 	GetUserRoles(userID uint) ([]models.Role, error) | ||||||
|  | 	AssignRole(userID uint, roleID uint) error | ||||||
|  | 	RemoveRole(userID uint, roleID uint) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUserByUsername(username string) (*models.User, error) { | type userRepository struct { | ||||||
| 	var user models.User | 	*BaseRepository | ||||||
| 	result := db.First(&user, "username = ?", username) |  | ||||||
| 	return &user, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func CreateUser(user *models.User) (*models.User, error) { | func NewUserRepository(db *gorm.DB) UserRepository { | ||||||
| 	result := db.Create(user) | 	return &userRepository{ | ||||||
| 	return user, result.Error | 		BaseRepository: NewBaseRepository(db), | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func UpdateUser(id string, updateData map[string]interface{}) (*models.User, error) { |  | ||||||
| 	var user models.User |  | ||||||
| 	result := db.Model(&user).Where("id = ?", id).Updates(updateData) |  | ||||||
| 	if result.Error != nil { |  | ||||||
| 		return nil, result.Error |  | ||||||
| 	} | 	} | ||||||
| 	return GetUserByID(id) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func DeleteUser(id string) error { | func (r *userRepository) Create(user *models.User) error { | ||||||
| 	result := db.Delete(&models.User{}, "id = ?", id) | 	return r.BaseRepository.Create(user) | ||||||
| 	return result.Error |  | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) Update(user *models.User) error { | ||||||
|  | 	return r.BaseRepository.Update(user) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) Delete(user *models.User) error { | ||||||
|  | 	return r.BaseRepository.Delete(user) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) FindByID(id uint) (*models.User, error) { | ||||||
|  | 	var user models.User | ||||||
|  | 	err := r.db.Preload("Roles").First(&user, id).Error | ||||||
|  | 	return &user, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) FindAll() ([]models.User, error) { | ||||||
|  | 	var users []models.User | ||||||
|  | 	err := r.BaseRepository.FindAll(&users, "Roles") | ||||||
|  | 	return users, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) FindByUsername(username string) (*models.User, error) { | ||||||
|  | 	var user models.User | ||||||
|  | 	err := r.db.Where("username = ?", username).First(&user).Error | ||||||
|  | 	return &user, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) GetUserRoles(userID uint) ([]models.Role, error) { | ||||||
|  | 	var roles []models.Role | ||||||
|  | 	err := r.db.Model(&models.User{ID: userID}).Association("Roles").Find(&roles) | ||||||
|  | 	return roles, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) AssignRole(userID uint, roleID uint) error { | ||||||
|  | 	return r.db.Model(&models.User{ID: userID}).Association("Roles").Append(&models.Role{ID: roleID}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userRepository) RemoveRole(userID uint, roleID uint) error { | ||||||
|  | 	return r.db.Model(&models.User{ID: userID}).Association("Roles").Delete(&models.Role{ID: roleID}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -1,61 +1,55 @@ | |||||||
| package repositories | package repositories | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func CreateUserGroup(userGroup *models.UserGroup) (*models.UserGroup, error) { | type UserGroupRepository interface { | ||||||
| 	result := db.Create(userGroup) | 	Create(group *models.UserGroup) error | ||||||
| 	return userGroup, result.Error | 	Update(group *models.UserGroup) error | ||||||
|  | 	Delete(group *models.UserGroup) error | ||||||
|  | 	FindByID(id uint) (*models.UserGroup, error) | ||||||
|  | 	FindAll() ([]models.UserGroup, error) | ||||||
|  | 	FindByName(name string) (*models.UserGroup, error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUserGroupByID(id uint) (*models.UserGroup, error) { | type userGroupRepository struct { | ||||||
| 	var userGroup models.UserGroup | 	*BaseRepository | ||||||
| 	result := db.Preload("Users").Preload("Roles").First(&userGroup, id) |  | ||||||
| 	return &userGroup, result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func GetUserGroups() ([]models.UserGroup, error) { | func NewUserGroupRepository(db *gorm.DB) UserGroupRepository { | ||||||
| 	var userGroups []models.UserGroup | 	return &userGroupRepository{ | ||||||
| 	result := db.Preload("Users").Preload("Roles").Find(&userGroups) | 		BaseRepository: NewBaseRepository(db), | ||||||
| 	return userGroups, result.Error |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func UpdateUserGroup(id uint, updateData map[string]interface{}) (*models.UserGroup, error) { |  | ||||||
| 	var userGroup models.UserGroup |  | ||||||
| 	result := db.Model(&userGroup).Where("id = ?", id).Updates(updateData) |  | ||||||
| 	if result.Error != nil { |  | ||||||
| 		return nil, result.Error |  | ||||||
| 	} | 	} | ||||||
| 	return GetUserGroupByID(id) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func DeleteUserGroup(id uint) error { | func (r *userGroupRepository) Create(group *models.UserGroup) error { | ||||||
| 	result := db.Delete(&models.UserGroup{}, id) | 	return r.BaseRepository.Create(group) | ||||||
| 	return result.Error |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func AddUserToGroup(userGroupID uint, userID uint) error { | func (r *userGroupRepository) Update(group *models.UserGroup) error { | ||||||
| 	return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}). | 	return r.BaseRepository.Update(group) | ||||||
| 		Association("Users"). |  | ||||||
| 		Append(&models.User{Model: gorm.Model{ID: userID}}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func RemoveUserFromGroup(userGroupID uint, userID uint) error { | func (r *userGroupRepository) Delete(group *models.UserGroup) error { | ||||||
| 	return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}). | 	return r.BaseRepository.Delete(group) | ||||||
| 		Association("Users"). |  | ||||||
| 		Delete(&models.User{Model: gorm.Model{ID: userID}}) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func AddRoleToGroup(userGroupID uint, roleID uint) error { | func (r *userGroupRepository) FindByID(id uint) (*models.UserGroup, error) { | ||||||
| 	return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}). | 	var group models.UserGroup | ||||||
| 		Association("Roles"). | 	err := r.BaseRepository.FindByID(&group, id) | ||||||
| 		Append(&models.Role{Model: gorm.Model{ID: roleID}}) | 	return &group, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func RemoveRoleFromGroup(userGroupID uint, roleID uint) error { | func (r *userGroupRepository) FindAll() ([]models.UserGroup, error) { | ||||||
| 	return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}). | 	var groups []models.UserGroup | ||||||
| 		Association("Roles"). | 	err := r.BaseRepository.FindAll(&groups) | ||||||
| 		Delete(&models.Role{Model: gorm.Model{ID: roleID}}) | 	return groups, err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *userGroupRepository) FindByName(name string) (*models.UserGroup, error) { | ||||||
|  | 	var group models.UserGroup | ||||||
|  | 	err := r.db.Where("name = ?", name).First(&group).Error | ||||||
|  | 	return &group, err | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,27 +1,16 @@ | |||||||
| package server | package server | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/api" | 	"fmt" | ||||||
| 	// "gitea.zjmud.xyz/phyer/rbac/config" | 	"net/http" | ||||||
|  | 
 | ||||||
| 	"github.com/gin-gonic/gin" | 	"github.com/gin-gonic/gin" | ||||||
| 	// "gorm.io/driver/mysql" |  | ||||||
| 	// "gorm.io/gorm" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // InitDB is now handled in repositories package | func StartServer(router *gin.Engine, cfg *config.Config) { | ||||||
| 
 | 	addr := fmt.Sprintf(":%s", cfg.ServerPort) | ||||||
| // NewServer creates and returns a new Gin server | 	fmt.Printf("Starting server on %s\n", addr) | ||||||
| func NewServer() *gin.Engine { | 	if err := router.Run(addr); err != nil { | ||||||
| 	r := gin.Default() | 		panic(err) | ||||||
| 	return r | 	} | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func Start() { |  | ||||||
| 	r := gin.Default() |  | ||||||
| 
 |  | ||||||
| 	// 初始化路由 |  | ||||||
| 	api.SetupRoutes(r) |  | ||||||
| 
 |  | ||||||
| 	// 启动服务器 |  | ||||||
| 	r.Run(":8080") |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,27 +1,31 @@ | |||||||
| package services | package services | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"gitea.zjmud.com/phyer/rbac/models" | ||||||
| 	// "gitea.zjmud.xyz/phyer/rbac/models" | 	"gitea.zjmud.com/phyer/rbac/repositories" | ||||||
| 	"strconv" | 	"gorm.io/gorm" | ||||||
| 
 |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/repositories" |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/utils" |  | ||||||
| 	"golang.org/x/crypto/bcrypt" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Login(username, password string) (string, error) { | type AuthService struct { | ||||||
| 	user, err := repositories.GetUserByUsername(username) | 	userRepo repositories.UserRepository | ||||||
| 	if err != nil { | } | ||||||
| 		return "", errors.New("invalid credentials") | 
 | ||||||
| 	} | func NewAuthService(db *gorm.DB) *AuthService { | ||||||
| 	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) | 	return &AuthService{ | ||||||
| 	if err != nil { | 		userRepo: repositories.NewUserRepository(db), | ||||||
| 		return "", errors.New("invalid credentials") | 	} | ||||||
| 	} | } | ||||||
| 	token, err := utils.GenerateJWT(strconv.FormatUint(uint64(user.ID), 10)) | 
 | ||||||
| 	if err != nil { | func (s *AuthService) Authenticate(username, password string) (*models.User, error) { | ||||||
| 		return "", err | 	user, err := s.userRepo.FindByUsername(username) | ||||||
| 	} | 	if err != nil { | ||||||
| 	return token, nil | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hashedPassword, err := models.HashPassword(password) | ||||||
|  | 	if err != nil || string(hashedPassword) != user.Password { | ||||||
|  | 		return nil, ErrInvalidCredentials | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return user, nil | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										237
									
								
								services/rbac.go
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								services/rbac.go
									
									
									
									
									
								
							| @ -1,237 +0,0 @@ | |||||||
| package services |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"strconv" |  | ||||||
| 
 |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/repositories" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // AssignRoleToUser 为用户分配角色 |  | ||||||
| func AssignRoleToUser(userID uint, roleID uint) error { |  | ||||||
| 	// 检查用户是否存在 |  | ||||||
| 	user, err := repositories.GetUserByID(strconv.FormatUint(uint64(userID), 10)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("user not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 检查角色是否存在 |  | ||||||
| 	role, err := repositories.GetRoleByID(roleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("role not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 分配角色 |  | ||||||
| 	return repositories.AssignRoleToUser(user.ID, role.ID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RemoveRoleFromUser 移除用户的角色 |  | ||||||
| func RemoveRoleFromUser(userID uint, roleID uint) error { |  | ||||||
| 	// 检查用户是否存在 |  | ||||||
| 	user, err := repositories.GetUserByID(strconv.FormatUint(uint64(userID), 10)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("user not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 检查角色是否存在 |  | ||||||
| 	role, err := repositories.GetRoleByID(roleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("role not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 移除角色 |  | ||||||
| 	return repositories.RemoveRoleFromUser(user.ID, role.ID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CreateRoleWithPermissions 创建角色并分配权限 |  | ||||||
| func CreateRoleWithPermissions(roleName string, permissionIDs []uint) (*models.Role, error) { |  | ||||||
| 	// 检查角色是否已存在 |  | ||||||
| 	exists, err := repositories.CheckRoleExists(roleName) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if exists { |  | ||||||
| 		return nil, errors.New("role already exists") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 创建角色 |  | ||||||
| 	role := &models.Role{Name: roleName} |  | ||||||
| 	role, err = repositories.CreateRole(role) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 为角色分配权限 |  | ||||||
| 	for _, permissionID := range permissionIDs { |  | ||||||
| 		err = repositories.AddPermissionToRole(role.ID, permissionID) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return role, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CreateRole 创建新角色 |  | ||||||
| func CreateRole(name, description string) (*models.Role, error) { |  | ||||||
| 	// 检查角色是否已存在 |  | ||||||
| 	exists, err := repositories.CheckRoleExists(name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if exists { |  | ||||||
| 		return nil, errors.New("role already exists") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 创建角色 |  | ||||||
| 	role := &models.Role{ |  | ||||||
| 		Name: name, |  | ||||||
| 	} |  | ||||||
| 	return repositories.CreateRole(role) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetAllRoles 获取所有角色 |  | ||||||
| func GetAllRoles() ([]models.Role, error) { |  | ||||||
| 	return repositories.GetAllRoles() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CreatePermission 创建新权限 |  | ||||||
| func CreatePermission(name, description, resource, action string) (*models.Permission, error) { |  | ||||||
| 	// 检查权限是否已存在 |  | ||||||
| 	exists, err := repositories.CheckPermissionExists(name) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if exists { |  | ||||||
| 		return nil, errors.New("permission already exists") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 创建权限 |  | ||||||
| 	permission := &models.Permission{ |  | ||||||
| 		Name:     name, |  | ||||||
| 		Resource: resource, |  | ||||||
| 		Action:   action, |  | ||||||
| 	} |  | ||||||
| 	return repositories.CreatePermission(permission) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // AssignPermissionToRole 为角色分配权限 |  | ||||||
| func AssignPermissionToRole(roleID, permissionID uint) error { |  | ||||||
| 	// 检查角色是否存在 |  | ||||||
| 	_, err := repositories.GetRoleByID(roleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("role not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 检查权限是否存在 |  | ||||||
| 	_, err = repositories.GetPermissionByID(permissionID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("permission not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 分配权限 |  | ||||||
| 	return repositories.AddPermissionToRole(roleID, permissionID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetAllPermissions 获取所有权限 |  | ||||||
| func GetAllPermissions() ([]models.Permission, error) { |  | ||||||
| 	return repositories.GetPermissions() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetRoleByID 根据ID获取角色 |  | ||||||
| func GetRoleByID(roleID uint) (*models.Role, error) { |  | ||||||
| 	return repositories.GetRoleByID(roleID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UpdateRole 更新角色 |  | ||||||
| func UpdateRole(roleID uint, updateData map[string]interface{}) (*models.Role, error) { |  | ||||||
| 	// 检查角色是否存在 |  | ||||||
| 	_, err := repositories.GetRoleByID(roleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errors.New("role not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 更新角色 |  | ||||||
| 	return repositories.UpdateRole(roleID, updateData) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeleteRole 删除角色 |  | ||||||
| func DeleteRole(roleID uint) error { |  | ||||||
| 	// 检查角色是否存在 |  | ||||||
| 	_, err := repositories.GetRoleByID(roleID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("role not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 删除角色 |  | ||||||
| 	return repositories.DeleteRole(roleID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetPermissionByID 根据ID获取权限 |  | ||||||
| func GetPermissionByID(permissionID uint) (*models.Permission, error) { |  | ||||||
| 	return repositories.GetPermissionByID(permissionID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UpdatePermission 更新权限 |  | ||||||
| func UpdatePermission(permissionID uint, updateData map[string]interface{}) (*models.Permission, error) { |  | ||||||
| 	// 检查权限是否存在 |  | ||||||
| 	_, err := repositories.GetPermissionByID(permissionID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, errors.New("permission not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 更新权限 |  | ||||||
| 	return repositories.UpdatePermission(permissionID, updateData) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // DeletePermission 删除权限 |  | ||||||
| func DeletePermission(permissionID uint) error { |  | ||||||
| 	// 检查权限是否存在 |  | ||||||
| 	_, err := repositories.GetPermissionByID(permissionID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return errors.New("permission not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 删除权限 |  | ||||||
| 	return repositories.DeletePermission(permissionID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // CheckUserPermission 检查用户是否具有特定权限 |  | ||||||
| // CheckUserPermission 检查用户是否具有特定权限 |  | ||||||
| func CheckUserPermission(userID string, permission string) (bool, error) { |  | ||||||
| 	// 获取用户的所有角色 |  | ||||||
| 	user, err := repositories.GetUserByID(userID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return false, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 检查每个角色的权限 |  | ||||||
| 	for _, role := range user.Roles { |  | ||||||
| 		for _, perm := range role.Permissions { |  | ||||||
| 			if perm.Name == permission { |  | ||||||
| 				return true, nil |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return false, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetUserPermissions 获取用户的所有权限 |  | ||||||
| func GetUserPermissions(userID string) ([]string, error) { |  | ||||||
| 	var permissions []string |  | ||||||
| 	user, err := repositories.GetUserByID(userID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// 收集所有角色的权限 |  | ||||||
| 	for _, role := range user.Roles { |  | ||||||
| 		for _, perm := range role.Permissions { |  | ||||||
| 			permissions = append(permissions, perm.Name) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return permissions, nil |  | ||||||
| } |  | ||||||
| @ -1,46 +0,0 @@ | |||||||
| package services |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/models" |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/repositories" |  | ||||||
| 
 |  | ||||||
| 	// "gitea.zjmud.xyz/phyer/rbac/utils" |  | ||||||
| 	"golang.org/x/crypto/bcrypt" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func GetAllUsers() ([]models.User, error) { |  | ||||||
| 	return repositories.GetAllUsers() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func GetUserByID(id string) (*models.User, error) { |  | ||||||
| 	return repositories.GetUserByID(id) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func UpdateUser(id string, updateData map[string]interface{}) (*models.User, error) { |  | ||||||
| 	if password, ok := updateData["password"]; ok { |  | ||||||
| 		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password.(string)), bcrypt.DefaultCost) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		updateData["password"] = string(hashedPassword) |  | ||||||
| 	} |  | ||||||
| 	return repositories.UpdateUser(id, updateData) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func DeleteUser(id string) error { |  | ||||||
| 	return repositories.DeleteUser(id) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func RegisterUser(username, fullname, password, email string) (*models.User, error) { |  | ||||||
| 	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	user := &models.User{ |  | ||||||
| 		Username: username, |  | ||||||
| 		Fullname: fullname, |  | ||||||
| 		Password: string(hashedPassword), |  | ||||||
| 		Email:    email, |  | ||||||
| 	} |  | ||||||
| 	return repositories.CreateUser(user) |  | ||||||
| } |  | ||||||
							
								
								
									
										41
									
								
								utils/jwt.go
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								utils/jwt.go
									
									
									
									
									
								
							| @ -1,31 +1,38 @@ | |||||||
| package utils | package utils | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" |  | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/config" |  | ||||||
| 	"github.com/golang-jwt/jwt/v5" | 	"github.com/golang-jwt/jwt/v5" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func GenerateJWT(userID string) (string, error) { | var JWTSecret = []byte("your-secret-key") | ||||||
| 	claims := jwt.MapClaims{ | 
 | ||||||
| 		"user_id": userID, | type Claims struct { | ||||||
| 		"exp":     time.Now().Add(time.Hour * 24).Unix(), | 	UserID uint `json:"user_id"` | ||||||
| 	} | 	jwt.RegisteredClaims | ||||||
| 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |  | ||||||
| 	return token.SignedString([]byte(config.AppConfig.JWTSecret)) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ParseJWT(tokenString string) (jwt.MapClaims, error) { | func GenerateToken(userID uint) (string, error) { | ||||||
| 	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { | 	expirationTime := time.Now().Add(24 * time.Hour) | ||||||
| 		return []byte(config.AppConfig.JWTSecret), nil | 	claims := &Claims{ | ||||||
| 	}) | 		UserID: userID, | ||||||
| 	if err != nil { | 		RegisteredClaims: jwt.RegisteredClaims{ | ||||||
| 		return nil, err | 			ExpiresAt: jwt.NewNumericDate(expirationTime), | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { | 
 | ||||||
|  | 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) | ||||||
|  | 	return token.SignedString(JWTSecret) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ParseToken(tokenString string) (*Claims, error) { | ||||||
|  | 	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { | ||||||
|  | 		return JWTSecret, nil | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	if claims, ok := token.Claims.(*Claims); ok && token.Valid { | ||||||
| 		return claims, nil | 		return claims, nil | ||||||
| 	} | 	} | ||||||
| 	return nil, errors.New("invalid token") | 	return nil, err | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,83 +0,0 @@ | |||||||
| package utils |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"fmt" |  | ||||||
| 	"time" |  | ||||||
| 
 |  | ||||||
| 	"gitea.zjmud.xyz/phyer/rbac/config" |  | ||||||
| 	"github.com/go-redis/redis/v8" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| var ( |  | ||||||
| 	RedisClient *redis.Client |  | ||||||
| 	ctx         = context.Background() |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // InitRedis 初始化 Redis 连接 |  | ||||||
| func InitRedis() error { |  | ||||||
| 	RedisClient = redis.NewClient(&redis.Options{ |  | ||||||
| 		Addr:     fmt.Sprintf("%s:%d", config.AppConfig.RedisHost, config.AppConfig.RedisPort), |  | ||||||
| 		Password: config.AppConfig.RedisPassword, |  | ||||||
| 		DB:       config.AppConfig.RedisDB, // 使用默认数据库 |  | ||||||
| 	}) |  | ||||||
| 
 |  | ||||||
| 	// 测试连接 |  | ||||||
| 	_, err := RedisClient.Ping(ctx).Result() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("failed to connect to Redis: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Set 设置键值对,带过期时间 |  | ||||||
| func Set(key string, value interface{}, expiration time.Duration) error { |  | ||||||
| 	return RedisClient.Set(ctx, key, value, expiration).Err() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Get 获取键值 |  | ||||||
| func Get(key string) (string, error) { |  | ||||||
| 	return RedisClient.Get(ctx, key).Result() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Delete 删除键 |  | ||||||
| func Delete(key string) error { |  | ||||||
| 	return RedisClient.Del(ctx, key).Err() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Exists 检查键是否存在 |  | ||||||
| func Exists(key string) (bool, error) { |  | ||||||
| 	result, err := RedisClient.Exists(ctx, key).Result() |  | ||||||
| 	return result == 1, err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Incr 自增键值 |  | ||||||
| func Incr(key string) (int64, error) { |  | ||||||
| 	return RedisClient.Incr(ctx, key).Result() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Decr 自减键值 |  | ||||||
| func Decr(key string) (int64, error) { |  | ||||||
| 	return RedisClient.Decr(ctx, key).Result() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HSet 设置哈希字段值 |  | ||||||
| func HSet(key string, field string, value interface{}) error { |  | ||||||
| 	return RedisClient.HSet(ctx, key, field, value).Err() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HGet 获取哈希字段值 |  | ||||||
| func HGet(key string, field string) (string, error) { |  | ||||||
| 	return RedisClient.HGet(ctx, key, field).Result() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HGetAll 获取哈希所有字段值 |  | ||||||
| func HGetAll(key string) (map[string]string, error) { |  | ||||||
| 	return RedisClient.HGetAll(ctx, key).Result() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Expire 设置键的过期时间 |  | ||||||
| func Expire(key string, expiration time.Duration) error { |  | ||||||
| 	return RedisClient.Expire(ctx, key, expiration).Err() |  | ||||||
| } |  | ||||||
| @ -1,44 +1,25 @@ | |||||||
| package utils | package utils | ||||||
| 
 | 
 | ||||||
| import ( | import "github.com/gin-gonic/gin" | ||||||
| 	"github.com/gin-gonic/gin" |  | ||||||
| ) |  | ||||||
| 
 | 
 | ||||||
| // SuccessResponse 成功响应结构 | type Response struct { | ||||||
| type SuccessResponse struct { |  | ||||||
| 	Code    int         `json:"code"` | 	Code    int         `json:"code"` | ||||||
| 	Message string      `json:"message"` | 	Message string      `json:"message"` | ||||||
| 	Data    interface{} `json:"data"` | 	Data    interface{} `json:"data"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ErrorResponse 错误响应结构 | func Success(c *gin.Context, data interface{}) { | ||||||
| type ErrorResponse struct { | 	c.JSON(200, Response{ | ||||||
| 	Code    int    `json:"code"` | 		Code:    200, | ||||||
| 	Message string `json:"message"` | 		Message: "success", | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RespondSuccess 返回成功响应 |  | ||||||
| func RespondSuccess(c *gin.Context, code int, message string, data interface{}) { |  | ||||||
| 	c.JSON(code, SuccessResponse{ |  | ||||||
| 		Code:    code, |  | ||||||
| 		Message: message, |  | ||||||
| 		Data:    data, | 		Data:    data, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RespondError 返回错误响应 | func Error(c *gin.Context, code int, message string) { | ||||||
| func RespondError(c *gin.Context, code int, message string) { | 	c.JSON(code, Response{ | ||||||
| 	c.JSON(code, ErrorResponse{ |  | ||||||
| 		Code:    code, | 		Code:    code, | ||||||
| 		Message: message, | 		Message: message, | ||||||
| 	}) | 		Data:    nil, | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RespondValidationError 返回验证错误响应 |  | ||||||
| func RespondValidationError(c *gin.Context, errors map[string]string) { |  | ||||||
| 	c.JSON(400, gin.H{ |  | ||||||
| 		"code":    400, |  | ||||||
| 		"message": "Validation error", |  | ||||||
| 		"errors":  errors, |  | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zhangkun9038@dingtalk.com
						zhangkun9038@dingtalk.com