diff --git a/config/config.go b/config/config.go index 2e4f8b0..d35e8a8 100644 --- a/config/config.go +++ b/config/config.go @@ -5,12 +5,20 @@ import ( "strconv" ) +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 { - DBHost string - DBPort int - DBUser string - DBPassword string - DBName string + DB DBConfig JWTSecret string RedisHost string RedisPort int @@ -21,11 +29,13 @@ var AppConfig Config func Init() { AppConfig = Config{ - DBHost: getEnv("DB_HOST", "localhost"), - DBPort: getEnvAsInt("DB_PORT", 3306), - DBUser: getEnv("DB_USER", "root"), - DBPassword: getEnv("DB_PASSWORD", ""), - DBName: getEnv("DB_NAME", "rbac"), + DB: DBConfig{ + Host: getEnv("DB_HOST", "localhost"), + Port: getEnvAsInt("DB_PORT", 3306), + User: getEnv("DB_USER", "root"), + Password: getEnv("DB_PASSWORD", ""), + Name: getEnv("DB_NAME", "rbac"), + }, JWTSecret: getEnv("JWT_SECRET", "secret"), RedisHost: getEnv("REDIS_HOST", "localhost"), RedisPort: getEnvAsInt("REDIS_PORT", 6379), diff --git a/controllers/rbac.go b/controllers/rbac.go index 99c42ba..021d496 100644 --- a/controllers/rbac.go +++ b/controllers/rbac.go @@ -3,6 +3,7 @@ package controllers import ( "gitea.zjmud.xyz/phyer/rbac/services" "github.com/gin-gonic/gin" + "strconv" ) // CreateRole 创建新角色 @@ -93,6 +94,63 @@ func AssignPermissionToRole(c *gin.Context) { 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() @@ -102,3 +160,60 @@ func GetPermissions(c *gin.Context) { } 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"}) +} diff --git a/main.go b/main.go index f4ff213..504821b 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,4 @@ +<<<<<<< HEAD package main import ( @@ -13,6 +14,23 @@ func main() { api.SetupRoutes(r) r.Run(":8080") } +======= +package main + +import ( + "gitea.zjmud.xyz/phyer/rbac/api" + "gitea.zjmud.xyz/phyer/rbac/config" + "gitea.zjmud.xyz/phyer/rbac/server" +) + +func main() { + config.Init() + server.InitDB() + r := server.NewServer() + api.SetupRoutes(r) + r.Run(":8080") +} +>>>>>>> Snippet // package main // diff --git a/middleware/auth.go b/middleware/auth.go index f12bd72..9018bcd 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -5,6 +5,11 @@ import ( "github.com/gin-gonic/gin" ) +// JWTAuth is an alias for AuthMiddleware +func JWTAuth() gin.HandlerFunc { + return AuthMiddleware() +} + func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("Authorization") diff --git a/models/user.go b/models/user.go index d0566ab..0022fb9 100644 --- a/models/user.go +++ b/models/user.go @@ -1,11 +1,12 @@ package models import ( + "gorm.io/gorm" "time" ) type User struct { - ID string `json:"id" gorm:"primaryKey"` + gorm.Model Username string `json:"username" gorm:"uniqueIndex;not null"` Password string `json:"-" gorm:"not null"` Email string `json:"email" gorm:"uniqueIndex;not null"` diff --git a/rbac b/rbac new file mode 100755 index 0000000..4ea6190 Binary files /dev/null and b/rbac differ diff --git a/repositories/db.go b/repositories/db.go index 5f30871..061521c 100644 --- a/repositories/db.go +++ b/repositories/db.go @@ -2,15 +2,17 @@ package repositories import ( "gitea.zjmud.xyz/phyer/rbac/config" + "gitea.zjmud.xyz/phyer/rbac/models" "gorm.io/driver/mysql" "gorm.io/gorm" + "strconv" ) 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" + dsn := config.AppConfig.DB.User + ":" + config.AppConfig.DB.Password + "@tcp(" + config.AppConfig.DB.Host + ":" + strconv.Itoa(config.AppConfig.DB.Port) + ")/" + config.AppConfig.DB.Name + "?charset=utf8mb4&parseTime=True&loc=Local" db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { return err diff --git a/repositories/permission.go b/repositories/permission.go index 6f8d9dc..89ab88b 100644 --- a/repositories/permission.go +++ b/repositories/permission.go @@ -1,87 +1,55 @@ package repositories import ( - "gitea.zjmud.xyz/phyer/rbac/models" - "gorm.io/gorm" + "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 + 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 + 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) + 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) + result := db.Create(permission) + return permission, result.Error } func DeletePermission(id uint) error { - result := db.Delete(&models.Permission{}, id) - return result.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 + var count int64 + result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count) + return count > 0, result.Error } +func AssignRoleToUser(userID uint, roleID uint) error { + user := &models.User{Model: gorm.Model{ID: userID}} + role := &models.Role{Model: gorm.Model{ID: roleID}} + return db.Model(user).Association("Roles").Append(role) +} + +func RemoveRoleFromUser(userID uint, roleID uint) error { + user := &models.User{Model: gorm.Model{ID: userID}} + role := &models.Role{Model: gorm.Model{ID: roleID}} + return db.Model(user).Association("Roles").Delete(role) +} diff --git a/repositories/role.go b/repositories/role.go index dff1969..2c142b8 100644 --- a/repositories/role.go +++ b/repositories/role.go @@ -10,12 +10,30 @@ func CreateRole(role *models.Role) (*models.Role, error) { return role, result.Error } +func GetAllRoles() ([]models.Role, error) { + var roles []models.Role + result := db.Find(&roles) + return roles, result.Error +} + func GetRoleByID(id uint) (*models.Role, error) { var role models.Role - result := db.Preload("Permissions").First(&role, id) + 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) @@ -36,16 +54,6 @@ func DeleteRole(id uint) error { 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}}) } diff --git a/repositories/user.go b/repositories/user.go index 5a8cf7f..cc10cfe 100644 --- a/repositories/user.go +++ b/repositories/user.go @@ -1,20 +1,25 @@ package repositories import ( - "gitea.zjmud.xyz/phyer/rbac/config" "gitea.zjmud.xyz/phyer/rbac/models" - "gorm.io/gorm" + // "gorm.io/gorm" ) -var db *gorm.DB - -func InitDB() error { - var err error - db, err = gorm.Open(mysql.Open(config.GetDSN()), &gorm.Config{}) - if err != nil { - return err +func CheckUserPermission(userID string, permission string) (bool, error) { + var user models.User + result := db.Preload("Roles.Permissions").Where("id = ?", userID).First(&user) + if result.Error != nil { + return false, result.Error } - return db.AutoMigrate(&models.User{}) + + 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) { diff --git a/server/server.go b/server/server.go index f5ad1db..03b7fce 100644 --- a/server/server.go +++ b/server/server.go @@ -2,9 +2,30 @@ package server import ( "gitea.zjmud.xyz/phyer/rbac/api" + "gitea.zjmud.xyz/phyer/rbac/config" "github.com/gin-gonic/gin" + "gorm.io/driver/mysql" + "gorm.io/gorm" ) +var db *gorm.DB + +// InitDB initializes the database connection +func InitDB() { + var err error + dsn := config.AppConfig.DB.DSN() + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } +} + +// NewServer creates and returns a new Gin server +func NewServer() *gin.Engine { + r := gin.Default() + return r +} + func Start() { r := gin.Default() diff --git a/services/auth.go b/services/auth.go index 22ca269..29f99ef 100644 --- a/services/auth.go +++ b/services/auth.go @@ -2,10 +2,11 @@ package services import ( "errors" - "gitea.zjmud.xyz/phyer/rbac/models" + // "gitea.zjmud.xyz/phyer/rbac/models" "gitea.zjmud.xyz/phyer/rbac/repositories" "gitea.zjmud.xyz/phyer/rbac/utils" "golang.org/x/crypto/bcrypt" + "strconv" ) func Login(username, password string) (string, error) { @@ -17,7 +18,7 @@ func Login(username, password string) (string, error) { if err != nil { return "", errors.New("invalid credentials") } - token, err := utils.GenerateJWT(user.ID) + token, err := utils.GenerateJWT(strconv.FormatUint(uint64(user.ID), 10)) if err != nil { return "", err } diff --git a/services/rbac.go b/services/rbac.go index ef84729..195e752 100644 --- a/services/rbac.go +++ b/services/rbac.go @@ -4,12 +4,13 @@ import ( "errors" "gitea.zjmud.xyz/phyer/rbac/models" "gitea.zjmud.xyz/phyer/rbac/repositories" + "strconv" ) // AssignRoleToUser 为用户分配角色 -func AssignRoleToUser(userID string, roleID uint) error { +func AssignRoleToUser(userID uint, roleID uint) error { // 检查用户是否存在 - user, err := repositories.GetUserByID(userID) + user, err := repositories.GetUserByID(strconv.FormatUint(uint64(userID), 10)) if err != nil { return errors.New("user not found") } @@ -25,9 +26,9 @@ func AssignRoleToUser(userID string, roleID uint) error { } // RemoveRoleFromUser 移除用户的角色 -func RemoveRoleFromUser(userID string, roleID uint) error { +func RemoveRoleFromUser(userID uint, roleID uint) error { // 检查用户是否存在 - user, err := repositories.GetUserByID(userID) + user, err := repositories.GetUserByID(strconv.FormatUint(uint64(userID), 10)) if err != nil { return errors.New("user not found") } @@ -71,6 +72,131 @@ func CreateRoleWithPermissions(roleName string, permissionIDs []uint) (*models.R 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) { // 获取用户的所有角色 diff --git a/services/user.go b/services/user.go index 58220bf..91e79c8 100644 --- a/services/user.go +++ b/services/user.go @@ -3,7 +3,7 @@ package services import ( "gitea.zjmud.xyz/phyer/rbac/models" "gitea.zjmud.xyz/phyer/rbac/repositories" - "gitea.zjmud.xyz/phyer/rbac/utils" + // "gitea.zjmud.xyz/phyer/rbac/utils" "golang.org/x/crypto/bcrypt" ) diff --git a/tree.txt b/tree.txt index 2b23906..0215123 100644 --- a/tree.txt +++ b/tree.txt @@ -1,37 +1,41 @@ . ├── api -│ └── routes.go +│   └── routes.go ├── config -│ └── config.go +│   └── config.go ├── controllers -│ ├── auth.go -│ ├── rbac.go -│ └── user.go +│   ├── auth.go +│   ├── rbac.go +│   └── user.go ├── go.mod ├── go.sum ├── main.go ├── middleware -│ ├── auth.go -│ └── rbac.go +│   ├── auth.go +│   └── rbac.go ├── models -│ ├── permission.go -│ ├── role.go -│ ├── user.go -│ └── user_group.go +│   ├── permission.go +│   ├── role.go +│   ├── user.go +│   └── user_group.go +├── rbac ├── repositories -│ ├── permission.go -│ ├── role.go -│ ├── user.go -│ └── user_group.go +│   ├── db.go +│   ├── permission.go +│   ├── role.go +│   ├── user.go +│   └── user_group.go ├── server -│ └── server.go +│   └── server.go ├── services -│ ├── auth.go -│ ├── rbac.go -│ └── user.go -├── utils -│ ├── jwt.go -│ ├── redis.go -│ └── response.go +│   ├── auth.go +│   ├── rbac.go +│   └── user.go ├── sug.md -└── tree.txt +├── tree.txt +└── utils + ├── jwt.go + ├── redis.go + └── response.go + +10 directories, 29 files diff --git a/utils/jwt.go b/utils/jwt.go index 9e749ab..67d7430 100644 --- a/utils/jwt.go +++ b/utils/jwt.go @@ -1,6 +1,7 @@ package utils import ( + "errors" "gitea.zjmud.xyz/phyer/rbac/config" "github.com/golang-jwt/jwt/v5" "time"