up
This commit is contained in:
parent
af4d55d0d1
commit
ae75582d11
@ -0,0 +1,104 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/services"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateRole 创建新角色
|
||||
func CreateRole(c *gin.Context) {
|
||||
var roleData struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&roleData); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
role, err := services.CreateRole(roleData.Name, roleData.Description)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, role)
|
||||
}
|
||||
|
||||
// GetRoles 获取所有角色
|
||||
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) {
|
||||
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 {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
permission, err := services.CreatePermission(permissionData.Name, permissionData.Description, permissionData.Resource, permissionData.Action)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
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"})
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
7
go.mod
7
go.mod
@ -4,19 +4,24 @@ go 1.21
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||
golang.org/x/crypto v0.9.0
|
||||
gorm.io/gorm v1.25.2
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.7
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.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-sql-driver/mysql v1.7.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
|
26
go.sum
26
go.sum
@ -1,12 +1,18 @@
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/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/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
@ -21,6 +27,10 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
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/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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||
@ -47,6 +57,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
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/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/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
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/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@ -86,9 +102,15 @@ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cn
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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/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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
|
||||
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
||||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Permission struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"unique;not null"`
|
||||
Description string
|
||||
Resource string `gorm:"not null"`
|
||||
Action string `gorm:"not null"`
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Role struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"unique;not null"`
|
||||
Permissions []Permission `gorm:"many2many:role_permissions;"`
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserGroup 表示用户组模型
|
||||
type UserGroup struct {
|
||||
gorm.Model
|
||||
Name string `json:"name" gorm:"uniqueIndex;not null"` // 用户组名称
|
||||
Description string `json:"description"` // 用户组描述
|
||||
CreatedAt time.Time `json:"created_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;"` // 关联的角色
|
||||
}
|
19
repositories/db.go
Normal file
19
repositories/db.go
Normal file
@ -0,0 +1,19 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDB() error {
|
||||
var err error
|
||||
dsn := config.AppConfig.DBUser + ":" + config.AppConfig.DBPassword + "@tcp(" + config.AppConfig.DBHost + ":" + strconv.Itoa(config.AppConfig.DBPort) + ")/" + config.AppConfig.DBName + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.AutoMigrate(&models.Permission{}, &models.Role{}, &models.UserGroup{})
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreatePermission(permission *models.Permission) (*models.Permission, error) {
|
||||
result := db.Create(permission)
|
||||
return permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissionByID(id uint) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.First(&permission, id)
|
||||
return &permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissions() ([]models.Permission, error) {
|
||||
var permissions []models.Permission
|
||||
result := db.Find(&permissions)
|
||||
return permissions, result.Error
|
||||
}
|
||||
|
||||
func UpdatePermission(id uint, updateData map[string]interface{}) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.Model(&permission).Where("id = ?", id).Updates(updateData)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return GetPermissionByID(id)
|
||||
}
|
||||
|
||||
func DeletePermission(id uint) error {
|
||||
result := db.Delete(&models.Permission{}, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func CheckPermissionExists(name string) (bool, error) {
|
||||
var count int64
|
||||
result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count)
|
||||
return count > 0, result.Error
|
||||
}
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreatePermission(permission *models.Permission) (*models.Permission, error) {
|
||||
result := db.Create(permission)
|
||||
return permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissionByID(id uint) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.First(&permission, id)
|
||||
return &permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissions() ([]models.Permission, error) {
|
||||
var permissions []models.Permission
|
||||
result := db.Find(&permissions)
|
||||
return permissions, result.Error
|
||||
}
|
||||
|
||||
func UpdatePermission(id uint, updateData map[string]interface{}) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.Model(&permission).Where("id = ?", id).Updates(updateData)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return GetPermissionByID(id)
|
||||
}
|
||||
|
||||
func DeletePermission(id uint) error {
|
||||
result := db.Delete(&models.Permission{}, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func CheckPermissionExists(name string) (bool, error) {
|
||||
var count int64
|
||||
result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count)
|
||||
return count > 0, result.Error
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateRole(role *models.Role) (*models.Role, error) {
|
||||
result := db.Create(role)
|
||||
return role, result.Error
|
||||
}
|
||||
|
||||
func GetRoleByID(id uint) (*models.Role, error) {
|
||||
var role models.Role
|
||||
result := db.Preload("Permissions").First(&role, id)
|
||||
return &role, result.Error
|
||||
}
|
||||
|
||||
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)
|
||||
return 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 uint, permissionID uint) error {
|
||||
return db.Model(&models.Role{Model: gorm.Model{ID: roleID}}).Association("Permissions").Append(&models.Permission{Model: gorm.Model{ID: permissionID}})
|
||||
}
|
||||
|
||||
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}})
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateUserGroup(userGroup *models.UserGroup) (*models.UserGroup, error) {
|
||||
result := db.Create(userGroup)
|
||||
return userGroup, result.Error
|
||||
}
|
||||
|
||||
func GetUserGroupByID(id uint) (*models.UserGroup, error) {
|
||||
var userGroup models.UserGroup
|
||||
result := db.Preload("Users").Preload("Roles").First(&userGroup, id)
|
||||
return &userGroup, result.Error
|
||||
}
|
||||
|
||||
func GetUserGroups() ([]models.UserGroup, error) {
|
||||
var userGroups []models.UserGroup
|
||||
result := db.Preload("Users").Preload("Roles").Find(&userGroups)
|
||||
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 {
|
||||
result := db.Delete(&models.UserGroup{}, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func AddUserToGroup(userGroupID uint, userID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Users").
|
||||
Append(&models.User{Model: gorm.Model{ID: userID}})
|
||||
}
|
||||
|
||||
func RemoveUserFromGroup(userGroupID uint, userID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Users").
|
||||
Delete(&models.User{Model: gorm.Model{ID: userID}})
|
||||
}
|
||||
|
||||
func AddRoleToGroup(userGroupID uint, roleID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Roles").
|
||||
Append(&models.Role{Model: gorm.Model{ID: roleID}})
|
||||
}
|
||||
|
||||
func RemoveRoleFromGroup(userGroupID uint, roleID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Roles").
|
||||
Delete(&models.Role{Model: gorm.Model{ID: roleID}})
|
||||
}
|
110
services/rbac.go
110
services/rbac.go
@ -0,0 +1,110 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gitea.zjmud.xyz/phyer/rbac/repositories"
|
||||
)
|
||||
|
||||
// AssignRoleToUser 为用户分配角色
|
||||
func AssignRoleToUser(userID string, roleID uint) error {
|
||||
// 检查用户是否存在
|
||||
user, err := repositories.GetUserByID(userID)
|
||||
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 string, roleID uint) error {
|
||||
// 检查用户是否存在
|
||||
user, err := repositories.GetUserByID(userID)
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
917
sug.md
917
sug.md
@ -1,3 +1,4 @@
|
||||
|
||||
- Datetime: 2025-02-16 12:45:39
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
@ -1142,4 +1143,920 @@ func main() {
|
||||
|
||||
如果你需要其他模块的实现或有任何问题,请随时告诉我。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:12:44
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> models/user_group.go 需要什么内容
|
||||
>
|
||||
|
||||
`models/user_group.go` 文件应该定义用户组模型,用于将用户分组管理。以下是该文件的内容建议:
|
||||
|
||||
Filepath: models/user_group.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// UserGroup 表示用户组模型
|
||||
type UserGroup struct {
|
||||
gorm.Model
|
||||
Name string `json:"name" gorm:"uniqueIndex;not null"` // 用户组名称
|
||||
Description string `json:"description"` // 用户组描述
|
||||
CreatedAt time.Time `json:"created_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;"` // 关联的角色
|
||||
}
|
||||
|
||||
// UserGroupUser 表示用户和用户组的关联表
|
||||
type UserGroupUser struct {
|
||||
UserID uint `gorm:"primaryKey"` // 用户ID
|
||||
UserGroupID uint `gorm:"primaryKey"` // 用户组ID
|
||||
}
|
||||
|
||||
// UserGroupRole 表示用户组和角色的关联表
|
||||
type UserGroupRole struct {
|
||||
UserGroupID uint `gorm:"primaryKey"` // 用户组ID
|
||||
RoleID uint `gorm:"primaryKey"` // 角色ID
|
||||
}
|
||||
```
|
||||
|
||||
这个模型包含以下主要部分:
|
||||
|
||||
1. `UserGroup` 结构体:
|
||||
- 包含用户组的基本信息(名称、描述)
|
||||
- 使用 `gorm.Model` 包含默认字段(ID, CreatedAt, UpdatedAt, DeletedAt)
|
||||
- 通过 `many2many` 关联用户和角色
|
||||
|
||||
2. `UserGroupUser` 结构体:
|
||||
- 用于表示用户和用户组的多对多关系
|
||||
- 作为关联表,包含复合主键(UserID 和 UserGroupID)
|
||||
|
||||
3. `UserGroupRole` 结构体:
|
||||
- 用于表示用户组和角色的多对多关系
|
||||
- 作为关联表,包含复合主键(UserGroupID 和 RoleID)
|
||||
|
||||
这个模型设计允许:
|
||||
- 将用户分组管理
|
||||
- 为整个用户组分配角色
|
||||
- 灵活地管理用户和用户组之间的关系
|
||||
- 跟踪用户组的创建和更新时间
|
||||
|
||||
你可以根据需要扩展这个模型,例如添加更多字段或关联关系。如果需要实现具体的业务逻辑,还需要在 repositories 和 services 层添加相应的代码。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:16:15
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
- models/permission.go
|
||||
|
||||
> repositories/permission.go 这个文件用得上吗, 现在有一个 models/permission.gorm
|
||||
|
||||
是的,`repositories/permission.go` 文件是需要的。它负责处理与权限相关的数据库操作,而 `models/permission.go` 只是定义了权限的数据结构。让我们创建 `repositories/permission.go` 文件:
|
||||
|
||||
Filepath: repositories/permission.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreatePermission(permission *models.Permission) (*models.Permission, error) {
|
||||
result := db.Create(permission)
|
||||
return permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissionByID(id uint) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.First(&permission, id)
|
||||
return &permission, result.Error
|
||||
}
|
||||
|
||||
func GetPermissions() ([]models.Permission, error) {
|
||||
var permissions []models.Permission
|
||||
result := db.Find(&permissions)
|
||||
return permissions, result.Error
|
||||
}
|
||||
|
||||
func UpdatePermission(id uint, updateData map[string]interface{}) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.Model(&permission).Where("id = ?", id).Updates(updateData)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return GetPermissionByID(id)
|
||||
}
|
||||
|
||||
func DeletePermission(id uint) error {
|
||||
result := db.Delete(&models.Permission{}, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func CheckPermissionExists(name string) (bool, error) {
|
||||
var count int64
|
||||
result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count)
|
||||
return count > 0, result.Error
|
||||
}
|
||||
```
|
||||
|
||||
这个文件实现了以下功能:
|
||||
|
||||
1. `CreatePermission`: 创建新的权限
|
||||
2. `GetPermissionByID`: 根据ID获取权限
|
||||
3. `GetPermissions`: 获取所有权限列表
|
||||
4. `UpdatePermission`: 更新权限信息
|
||||
5. `DeletePermission`: 删除权限
|
||||
6. `CheckPermissionExists`: 检查权限名称是否已存在
|
||||
|
||||
这些方法将与 `models/permission.go` 中定义的 `Permission` 结构体一起工作,为权限管理提供完整的CRUD操作。
|
||||
|
||||
你还需要在 `repositories` 包中初始化数据库连接,可以在 `repositories/db.go` 中添加:
|
||||
|
||||
Filepath: repositories/db.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDB() error {
|
||||
var err error
|
||||
dsn := config.AppConfig.DBUser + ":" + config.AppConfig.DBPassword + "@tcp(" + config.AppConfig.DBHost + ":" + strconv.Itoa(config.AppConfig.DBPort) + ")/" + config.AppConfig.DBName + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.AutoMigrate(&models.Permission{})
|
||||
}
|
||||
```
|
||||
|
||||
这样,权限相关的数据库操作就完整了。你可以在服务层调用这些方法来处理业务逻辑。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:25:33
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- tree.txt
|
||||
|
||||
> repositories/role.go 需要吗
|
||||
|
||||
是的,`repositories/role.go` 是需要的。它负责处理与角色相关的数据库操作,与 `models/role.go` 配合使用。让我们创建这个文件:
|
||||
|
||||
Filepath: repositories/role.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateRole(role *models.Role) (*models.Role, error) {
|
||||
result := db.Create(role)
|
||||
return role, result.Error
|
||||
}
|
||||
|
||||
func GetRoleByID(id uint) (*models.Role, error) {
|
||||
var role models.Role
|
||||
result := db.Preload("Permissions").First(&role, id)
|
||||
return &role, result.Error
|
||||
}
|
||||
|
||||
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)
|
||||
return 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 uint, permissionID uint) error {
|
||||
return db.Model(&models.Role{Model: gorm.Model{ID: roleID}}).Association("Permissions").Append(&models.Permission{Model: gorm.Model{ID: permissionID}})
|
||||
}
|
||||
|
||||
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}})
|
||||
}
|
||||
```
|
||||
|
||||
这个文件实现了以下功能:
|
||||
|
||||
1. `CreateRole`: 创建新角色
|
||||
2. `GetRoleByID`: 根据ID获取角色(包含关联的权限)
|
||||
3. `GetRoles`: 获取所有角色列表(包含关联的权限)
|
||||
4. `UpdateRole`: 更新角色信息
|
||||
5. `DeleteRole`: 删除角色
|
||||
6. `CheckRoleExists`: 检查角色名称是否已存在
|
||||
7. `AddPermissionToRole`: 为角色添加权限
|
||||
8. `RemovePermissionFromRole`: 从角色中移除权限
|
||||
|
||||
这些方法将与 `models/role.go` 中定义的 `Role` 结构体一起工作,为角色管理提供完整的CRUD操作。
|
||||
|
||||
你还需要在 `repositories/db.go` 中添加对 `Role` 模型的自动迁移:
|
||||
|
||||
Filepath: repositories/db.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDB() error {
|
||||
var err error
|
||||
dsn := config.AppConfig.DBUser + ":" + config.AppConfig.DBPassword + "@tcp(" + config.AppConfig.DBHost + ":" + strconv.Itoa(config.AppConfig.DBPort) + ")/" + config.AppConfig.DBName + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.AutoMigrate(&models.Permission{}, &models.Role{})
|
||||
}
|
||||
```
|
||||
|
||||
这样,角色相关的数据库操作就完整了。你可以在服务层调用这些方法来处理业务逻辑。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:36:07
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> repositories/user_group.go 需要什么内容
|
||||
|
||||
`repositories/user_group.go` 文件用于处理与用户组相关的数据库操作。以下是该文件的内容建议:
|
||||
|
||||
Filepath: repositories/user_group.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateUserGroup(userGroup *models.UserGroup) (*models.UserGroup, error) {
|
||||
result := db.Create(userGroup)
|
||||
return userGroup, result.Error
|
||||
}
|
||||
|
||||
func GetUserGroupByID(id uint) (*models.UserGroup, error) {
|
||||
var userGroup models.UserGroup
|
||||
result := db.Preload("Users").Preload("Roles").First(&userGroup, id)
|
||||
return &userGroup, result.Error
|
||||
}
|
||||
|
||||
func GetUserGroups() ([]models.UserGroup, error) {
|
||||
var userGroups []models.UserGroup
|
||||
result := db.Preload("Users").Preload("Roles").Find(&userGroups)
|
||||
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 {
|
||||
result := db.Delete(&models.UserGroup{}, id)
|
||||
return result.Error
|
||||
}
|
||||
|
||||
func AddUserToGroup(userGroupID uint, userID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Users").
|
||||
Append(&models.User{Model: gorm.Model{ID: userID}})
|
||||
}
|
||||
|
||||
func RemoveUserFromGroup(userGroupID uint, userID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Users").
|
||||
Delete(&models.User{Model: gorm.Model{ID: userID}})
|
||||
}
|
||||
|
||||
func AddRoleToGroup(userGroupID uint, roleID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Roles").
|
||||
Append(&models.Role{Model: gorm.Model{ID: roleID}})
|
||||
}
|
||||
|
||||
func RemoveRoleFromGroup(userGroupID uint, roleID uint) error {
|
||||
return db.Model(&models.UserGroup{Model: gorm.Model{ID: userGroupID}}).
|
||||
Association("Roles").
|
||||
Delete(&models.Role{Model: gorm.Model{ID: roleID}})
|
||||
}
|
||||
```
|
||||
|
||||
这个文件实现了以下功能:
|
||||
|
||||
1. `CreateUserGroup`: 创建新用户组
|
||||
2. `GetUserGroupByID`: 根据ID获取用户组(包含关联的用户和角色)
|
||||
3. `GetUserGroups`: 获取所有用户组列表(包含关联的用户和角色)
|
||||
4. `UpdateUserGroup`: 更新用户组信息
|
||||
5. `DeleteUserGroup`: 删除用户组
|
||||
6. `AddUserToGroup`: 添加用户到用户组
|
||||
7. `RemoveUserFromGroup`: 从用户组中移除用户
|
||||
8. `AddRoleToGroup`: 为用户组添加角色
|
||||
9. `RemoveRoleFromGroup`: 从用户组中移除角色
|
||||
|
||||
这些方法将与 `models/user_group.go` 中定义的 `UserGroup` 结构体一起工作,为用户组管理提供完整的CRUD操作。
|
||||
|
||||
你还需要在 `repositories/db.go` 中添加对 `UserGroup` 模型的自动迁移:
|
||||
|
||||
Filepath: repositories/db.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gorm.io/driver/mysql"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDB() error {
|
||||
var err error
|
||||
dsn := config.AppConfig.DBUser + ":" + config.AppConfig.DBPassword + "@tcp(" + config.AppConfig.DBHost + ":" + strconv.Itoa(config.AppConfig.DBPort) + ")/" + config.AppConfig.DBName + "?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.AutoMigrate(&models.Permission{}, &models.Role{}, &models.UserGroup{})
|
||||
}
|
||||
```
|
||||
|
||||
这样,用户组相关的数据库操作就完整了。你可以在服务层调用这些方法来处理业务逻辑。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:40:54
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> services/rbac.go 需要什么内容
|
||||
>
|
||||
|
||||
`services/rbac.go` 文件应该包含与RBAC(基于角色的访问控制)相关的业务逻辑。以下是该文件的内容建议:
|
||||
|
||||
Filepath: services/rbac.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gitea.zjmud.xyz/phyer/rbac/repositories"
|
||||
)
|
||||
|
||||
// AssignRoleToUser 为用户分配角色
|
||||
func AssignRoleToUser(userID string, roleID uint) error {
|
||||
// 检查用户是否存在
|
||||
user, err := repositories.GetUserByID(userID)
|
||||
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 string, roleID uint) error {
|
||||
// 检查用户是否存在
|
||||
user, err := repositories.GetUserByID(userID)
|
||||
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
|
||||
}
|
||||
|
||||
// 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. `AssignRoleToUser`: 为用户分配角色
|
||||
2. `RemoveRoleFromUser`: 移除用户的角色
|
||||
3. `CreateRoleWithPermissions`: 创建角色并为其分配权限
|
||||
4. `CheckUserPermission`: 检查用户是否具有特定权限
|
||||
5. `GetUserPermissions`: 获取用户的所有权限
|
||||
|
||||
这些方法将作为RBAC系统的核心业务逻辑,被控制器层调用。它们处理了角色分配、权限检查等关键功能,同时通过调用仓库层的方法与数据库进行交互。
|
||||
|
||||
你可以根据具体需求扩展这个文件,例如添加更多与RBAC相关的业务逻辑,或者优化现有的功能实现。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:43:54
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> controllers/rbac.go 需要什么内容
|
||||
>
|
||||
|
||||
`controllers/rbac.go` 文件应该包含与RBAC(基于角色的访问控制)相关的控制器逻辑。以下是该文件的内容建议:
|
||||
|
||||
Filepath: controllers/rbac.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/services"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateRole 创建新角色
|
||||
func CreateRole(c *gin.Context) {
|
||||
var roleData struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&roleData); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
role, err := services.CreateRole(roleData.Name, roleData.Description)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(201, role)
|
||||
}
|
||||
|
||||
// GetRoles 获取所有角色
|
||||
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) {
|
||||
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 {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
permission, err := services.CreatePermission(permissionData.Name, permissionData.Description, permissionData.Resource, permissionData.Action)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
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"})
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
```
|
||||
|
||||
这个控制器文件实现了以下主要功能:
|
||||
|
||||
1. `CreateRole`: 创建新角色
|
||||
2. `GetRoles`: 获取所有角色列表
|
||||
3. `CreatePermission`: 创建新权限
|
||||
4. `AssignRoleToUser`: 为用户分配角色
|
||||
5. `AssignPermissionToRole`: 为角色分配权限
|
||||
6. `GetPermissions`: 获取所有权限列表
|
||||
|
||||
每个控制器方法都:
|
||||
- 解析请求数据
|
||||
- 调用相应的服务层方法
|
||||
- 处理错误并返回适当的HTTP响应
|
||||
|
||||
这些控制器方法将与 `services/rbac.go` 中的服务层方法配合使用,完成RBAC系统的核心功能。
|
||||
|
||||
你还需要在 `services/rbac.go` 中实现相应的服务层方法,以及在 `repositories` 包中实现数据库操作。如果需要这些文件的内容,请告诉我。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:47:16
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> utils/redis.go 需要什么内容
|
||||
>
|
||||
|
||||
`utils/redis.go` 文件用于初始化和管理 Redis 连接,并提供一些常用的 Redis 操作工具函数。以下是该文件的内容建议:
|
||||
|
||||
Filepath: utils/redis.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
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: 0, // 使用默认数据库
|
||||
})
|
||||
|
||||
// 测试连接
|
||||
_, 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. `InitRedis`: 初始化 Redis 连接,使用配置文件中的 Redis 连接信息
|
||||
2. `Set/Get`: 基本的键值对操作
|
||||
3. `Delete`: 删除键
|
||||
4. `Exists`: 检查键是否存在
|
||||
5. `Incr/Decr`: 自增/自减操作
|
||||
6. `HSet/HGet/HGetAll`: 哈希表操作
|
||||
7. `Expire`: 设置键的过期时间
|
||||
|
||||
使用示例:
|
||||
|
||||
```go
|
||||
// 初始化 Redis
|
||||
if err := utils.InitRedis(); err != nil {
|
||||
log.Fatalf("Failed to initialize Redis: %v", err)
|
||||
}
|
||||
|
||||
// 设置值
|
||||
err := utils.Set("mykey", "myvalue", time.Minute*10)
|
||||
if err != nil {
|
||||
log.Printf("Failed to set Redis key: %v", err)
|
||||
}
|
||||
|
||||
// 获取值
|
||||
value, err := utils.Get("mykey")
|
||||
if err != nil {
|
||||
log.Printf("Failed to get Redis key: %v", err)
|
||||
} else {
|
||||
log.Printf("Got value: %s", value)
|
||||
}
|
||||
```
|
||||
|
||||
这个 Redis 工具类可以用于缓存、会话管理、限流等场景。你可以根据需要扩展更多 Redis 操作函数。
|
||||
|
||||
---
|
||||
|
||||
- Datetime: 2025-02-16 18:51:26
|
||||
|
||||
- Model: alidsv3/deepseek-v3
|
||||
|
||||
- Selected files:
|
||||
- sug.md
|
||||
|
||||
> utils/response.go 这个文件需要吗
|
||||
>
|
||||
|
||||
是的,`utils/response.go` 文件是很有用的。它可以帮助我们统一 API 的响应格式,使代码更整洁和一致。让我们创建这个文件:
|
||||
|
||||
Filepath: utils/response.go
|
||||
Replace lines: 1-0
|
||||
```go
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SuccessResponse 成功响应结构
|
||||
type SuccessResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// ErrorResponse 错误响应结构
|
||||
type ErrorResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// RespondSuccess 返回成功响应
|
||||
func RespondSuccess(c *gin.Context, code int, message string, data interface{}) {
|
||||
c.JSON(code, SuccessResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// RespondError 返回错误响应
|
||||
func RespondError(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, ErrorResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
})
|
||||
}
|
||||
|
||||
// RespondValidationError 返回验证错误响应
|
||||
func RespondValidationError(c *gin.Context, errors map[string]string) {
|
||||
c.JSON(400, gin.H{
|
||||
"code": 400,
|
||||
"message": "Validation error",
|
||||
"errors": errors,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
这个文件提供了以下功能:
|
||||
|
||||
1. `SuccessResponse` 结构体:用于统一成功响应的格式
|
||||
2. `ErrorResponse` 结构体:用于统一错误响应的格式
|
||||
3. `RespondSuccess` 函数:用于返回成功的 API 响应
|
||||
4. `RespondError` 函数:用于返回错误的 API 响应
|
||||
5. `RespondValidationError` 函数:专门用于返回验证错误的响应
|
||||
|
||||
使用示例:
|
||||
|
||||
```go
|
||||
// 成功响应
|
||||
utils.RespondSuccess(c, http.StatusOK, "User created successfully", user)
|
||||
|
||||
// 错误响应
|
||||
utils.RespondError(c, http.StatusBadRequest, "Invalid input data")
|
||||
|
||||
// 验证错误响应
|
||||
utils.RespondValidationError(c, map[string]string{
|
||||
"username": "Username is required",
|
||||
"email": "Invalid email format",
|
||||
})
|
||||
```
|
||||
|
||||
这个工具文件可以帮助我们:
|
||||
1. 保持 API 响应格式的一致性
|
||||
2. 减少重复代码
|
||||
3. 更容易维护和修改响应格式
|
||||
4. 提供更清晰的错误信息
|
||||
|
||||
建议在控制器中统一使用这些响应函数,而不是直接使用 `c.JSON()`,这样可以确保整个项目的 API 响应格式一致。
|
||||
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"time"
|
||||
)
|
||||
|
||||
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: 0, // 使用默认数据库
|
||||
})
|
||||
|
||||
// 测试连接
|
||||
_, 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()
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// SuccessResponse 成功响应结构
|
||||
type SuccessResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
// ErrorResponse 错误响应结构
|
||||
type ErrorResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// RespondSuccess 返回成功响应
|
||||
func RespondSuccess(c *gin.Context, code int, message string, data interface{}) {
|
||||
c.JSON(code, SuccessResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// RespondError 返回错误响应
|
||||
func RespondError(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, ErrorResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
})
|
||||
}
|
||||
|
||||
// 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