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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/controllers"
|
||||
"gitea.zjmud.xyz/phyer/rbac/middleware"
|
||||
"gitea.zjmud.com/phyer/rbac/controllers"
|
||||
"gitea.zjmud.com/phyer/rbac/middleware"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRoutes(r *gin.Engine) {
|
||||
// 认证相关路由
|
||||
auth := r.Group("/auth")
|
||||
func SetupRouter(db *gorm.DB, redisClient *redis.Client) *gin.Engine {
|
||||
router := gin.Default()
|
||||
|
||||
// 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)
|
||||
auth.POST("/login", controllers.Login)
|
||||
authGroup.POST("/login", authController.Login)
|
||||
authGroup.POST("/register", authController.Register)
|
||||
}
|
||||
|
||||
// 需要认证的路由
|
||||
api := r.Group("/api")
|
||||
api.Use(middleware.JWTAuth())
|
||||
// Protected routes - Require JWT authentication
|
||||
apiGroup := router.Group("/api")
|
||||
apiGroup.Use(middleware.AuthMiddleware())
|
||||
{
|
||||
// 用户管理
|
||||
users := api.Group("/users")
|
||||
// User management routes
|
||||
userGroup := apiGroup.Group("/users")
|
||||
{
|
||||
users.GET("/", controllers.GetUsers)
|
||||
users.GET("/:id", controllers.GetUser)
|
||||
users.PUT("/:id", controllers.UpdateUser)
|
||||
users.DELETE("/:id", controllers.DeleteUser)
|
||||
userGroup.GET("", userController.GetUsers)
|
||||
userGroup.GET("/:id", userController.GetUserByID)
|
||||
}
|
||||
|
||||
// 角色管理
|
||||
roles := api.Group("/roles")
|
||||
// RBAC administration routes with additional authorization
|
||||
rbacGroup := apiGroup.Group("/rbac")
|
||||
rbacGroup.Use(middleware.RBACMiddleware())
|
||||
{
|
||||
roles.POST("/", controllers.CreateRole)
|
||||
roles.GET("/", controllers.GetRoles)
|
||||
roles.GET("/:id", controllers.GetRole)
|
||||
roles.PUT("/:id", controllers.UpdateRole)
|
||||
roles.DELETE("/:id", controllers.DeleteRole)
|
||||
rbacGroup.POST("/roles", rbacController.CreateRole)
|
||||
rbacGroup.POST("/permissions", rbacController.CreatePermission)
|
||||
rbacGroup.POST("/resources", rbacController.CreateResource)
|
||||
rbacGroup.POST("/resource-groups", rbacController.CreateResourceGroup)
|
||||
rbacGroup.POST("/actions", rbacController.CreateAction)
|
||||
rbacGroup.POST("/assignments", rbacController.AssignRoleToUser)
|
||||
}
|
||||
}
|
||||
|
||||
// 权限管理
|
||||
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")
|
||||
})
|
||||
}
|
||||
return router
|
||||
}
|
||||
|
@ -1,61 +1,60 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"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 {
|
||||
DB DBConfig
|
||||
JWTSecret string
|
||||
RedisHost string
|
||||
RedisPort int
|
||||
RedisPassword string
|
||||
DBHost string
|
||||
DBPort string
|
||||
DBUser string
|
||||
DBPassword string
|
||||
DBName string
|
||||
RedisAddr string
|
||||
RedisPass string
|
||||
RedisDB int
|
||||
ServerPort string
|
||||
}
|
||||
|
||||
var AppConfig Config
|
||||
|
||||
func Init() {
|
||||
AppConfig = Config{
|
||||
DB: DBConfig{
|
||||
Host: getEnv("DB_HOST", "192.168.65.5"),
|
||||
Port: getEnvAsInt("DB_PORT", 3306),
|
||||
User: getEnv("DB_USER", "root"),
|
||||
Password: getEnv("DB_PASSWORD", "d8db*#00oS"),
|
||||
Name: getEnv("DB_NAME", "rbac"),
|
||||
},
|
||||
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 LoadConfig() *Config {
|
||||
return &Config{
|
||||
DBHost: os.Getenv("DB_HOST"),
|
||||
DBPort: os.Getenv("DB_PORT"),
|
||||
DBUser: os.Getenv("DB_USER"),
|
||||
DBPassword: os.Getenv("DB_PASSWORD"),
|
||||
DBName: os.Getenv("DB_NAME"),
|
||||
RedisAddr: os.Getenv("REDIS_ADDR"),
|
||||
RedisPass: os.Getenv("REDIS_PASS"),
|
||||
RedisDB: 0,
|
||||
ServerPort: os.Getenv("SERVER_PORT"),
|
||||
}
|
||||
}
|
||||
|
||||
func getEnv(key, defaultValue string) string {
|
||||
if value, exists := os.LookupEnv(key); exists {
|
||||
return value
|
||||
func InitDB(cfg *Config) *gorm.DB {
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
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 {
|
||||
valueStr := getEnv(key, "")
|
||||
if value, err := strconv.Atoi(valueStr); err == nil {
|
||||
return value
|
||||
func InitRedis(cfg *Config) *redis.Client {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.RedisAddr,
|
||||
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
|
||||
|
||||
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/go-redis/redis/v8"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Register(c *gin.Context) {
|
||||
var registerData struct {
|
||||
Username string `json:"username"`
|
||||
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)
|
||||
type AuthController struct {
|
||||
DB *gorm.DB
|
||||
Redis *redis.Client
|
||||
}
|
||||
|
||||
func Login(c *gin.Context) {
|
||||
var loginData struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&loginData); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
token, err := services.Login(loginData.Username, loginData.Password)
|
||||
if err != nil {
|
||||
c.JSON(401, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"token": token})
|
||||
func NewAuthController(db *gorm.DB, redis *redis.Client) *AuthController {
|
||||
return &AuthController{DB: db, Redis: redis}
|
||||
}
|
||||
|
||||
func (ac *AuthController) Login(c *gin.Context) {
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
var req LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.Error(c, http.StatusBadRequest, "Invalid request format")
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
// "log"
|
||||
"net/http"
|
||||
|
||||
"strconv"
|
||||
|
||||
"gitea.zjmud.xyz/phyer/rbac/services"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CreateRole 创建新角色
|
||||
func CreateRole(c *gin.Context) {
|
||||
var roleData struct {
|
||||
type RBACController struct {
|
||||
DB *gorm.DB
|
||||
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"`
|
||||
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
|
||||
}
|
||||
|
||||
role, err := services.CreateRole(roleData.Name, roleData.Description)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
// 检查角色是否已存在
|
||||
roleRepo := repositories.NewRoleRepository(rc.DB)
|
||||
exists, err := roleRepo.ExistsByNameExcludeID(req.Name, 0)
|
||||
if err != nil || exists {
|
||||
utils.Error(c, http.StatusConflict, "Role already exists")
|
||||
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 获取所有角色
|
||||
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"})
|
||||
}
|
||||
// 其他RBAC相关方法...
|
||||
|
@ -1,50 +1,37 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/services"
|
||||
"net/http"
|
||||
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func GetUsers(c *gin.Context) {
|
||||
users, err := services.GetAllUsers()
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, users)
|
||||
type UserController struct {
|
||||
DB *gorm.DB
|
||||
Redis *redis.Client
|
||||
}
|
||||
|
||||
func GetUser(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
user, err := services.GetUserByID(id)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, user)
|
||||
func NewUserController(db *gorm.DB, redis *redis.Client) *UserController {
|
||||
return &UserController{DB: db, Redis: redis}
|
||||
}
|
||||
|
||||
func UpdateUser(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var updateData map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&updateData); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
func (uc *UserController) GetUsers(c *gin.Context) {
|
||||
var users []models.User
|
||||
if err := uc.DB.Find(&users).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to fetch users"})
|
||||
return
|
||||
}
|
||||
user, err := services.UpdateUser(id, updateData)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, user)
|
||||
c.JSON(http.StatusOK, users)
|
||||
}
|
||||
|
||||
func DeleteUser(c *gin.Context) {
|
||||
func (uc *UserController) GetUserByID(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
err := services.DeleteUser(id)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": err.Error()})
|
||||
var user models.User
|
||||
if err := uc.DB.First(&user, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
|
||||
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 (
|
||||
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
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/crypto v0.9.0
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/gorm v1.25.7
|
||||
github.com/go-redis/redis/v8 v8.11.5 // 使用存在的版本
|
||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||
gorm.io/driver/mysql v1.5.1
|
||||
gorm.io/gorm v1.25.4
|
||||
)
|
||||
|
||||
require github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.9.1 // 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/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
|
||||
@ -36,6 +35,7 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // 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/sys v0.8.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/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=
|
||||
@ -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/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/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/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
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-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/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/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
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/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
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/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=
|
||||
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
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/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-20220715151400-c0bba94af5f8/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/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/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/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=
|
||||
gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw=
|
||||
gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o=
|
||||
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
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=
|
||||
|
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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/api"
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gitea.zjmud.xyz/phyer/rbac/repositories"
|
||||
"gitea.zjmud.xyz/phyer/rbac/server"
|
||||
"log"
|
||||
|
||||
"gitea.zjmud.com/phyer/rbac/api"
|
||||
"gitea.zjmud.com/phyer/rbac/config"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config.Init()
|
||||
if err := repositories.InitDB(); err != nil {
|
||||
panic("failed to initialize database: " + err.Error())
|
||||
// 加载配置
|
||||
cfg := config.LoadConfig()
|
||||
|
||||
// 初始化数据库
|
||||
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 (
|
||||
"gitea.zjmud.xyz/phyer/rbac/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 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")
|
||||
if token == "" {
|
||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||
tokenString := c.GetHeader("Authorization")
|
||||
if tokenString == "" {
|
||||
utils.Error(c, http.StatusUnauthorized, "Authorization header required")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := utils.ParseJWT(token)
|
||||
claims, err := utils.ParseToken(tokenString)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"})
|
||||
utils.Error(c, http.StatusUnauthorized, "Invalid token")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
userID := claims["user_id"].(string)
|
||||
c.Set("userID", userID)
|
||||
c.Set("userID", claims.UserID)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,31 @@
|
||||
package middleware
|
||||
package middlewares
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/repositories"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func RBACMiddleware(permission string) gin.HandlerFunc {
|
||||
func RBACMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
userID := c.GetString("userID")
|
||||
if userID == "" {
|
||||
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
|
||||
// 获取用户ID
|
||||
userID, exists := c.Get("userID")
|
||||
if !exists {
|
||||
utils.Error(c, http.StatusForbidden, "User authentication required")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
hasPermission, err := repositories.CheckUserPermission(userID, permission)
|
||||
if err != nil || !hasPermission {
|
||||
c.AbortWithStatusJSON(403, gin.H{"error": "Forbidden"})
|
||||
return
|
||||
}
|
||||
// 获取请求方法和路径
|
||||
method := c.Request.Method
|
||||
path := c.FullPath()
|
||||
|
||||
// 这里需要实现RBAC检查逻辑(示例代码)
|
||||
// 实际应该查询用户的角色权限是否匹配当前请求
|
||||
// if !checkPermission(userID, method, path) {
|
||||
// utils.Error(c, http.StatusForbidden, "Access denied")
|
||||
// c.Abort()
|
||||
// return
|
||||
// }
|
||||
|
||||
c.Next()
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
package models
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import "time"
|
||||
|
||||
type Permission struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"unique;not null"`
|
||||
Description string
|
||||
Resource string `gorm:"not null"`
|
||||
Action string `gorm:"not null"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;size:50" json:"name"`
|
||||
Description string `gorm:"size:255" json:"description"`
|
||||
ResourceID uint `json:"resource_id"`
|
||||
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
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import "time"
|
||||
|
||||
type Role struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"unique;not null"`
|
||||
Permissions []Permission `gorm:"many2many:role_permissions;"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;size:50" json:"name"`
|
||||
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
|
||||
|
||||
import (
|
||||
// "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string `json:"username" gorm:"uniqueIndex;not null"`
|
||||
Fullname string `json:"fullname" gorm:"not null"`
|
||||
Password string `json:"-" gorm:"not null"`
|
||||
Email string `json:"email" gorm:"uniqueIndex;not null"`
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Username string `gorm:"uniqueIndex;size:50" json:"username"`
|
||||
Email string `gorm:"uniqueIndex;size:100" json:"email"`
|
||||
Password string `gorm:"size:255" json:"-"`
|
||||
CreatedAt time.Time `json:"created_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
|
||||
|
||||
import (
|
||||
"time"
|
||||
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;"` // 关联的角色
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;size:50" json:"name"`
|
||||
Description string `gorm:"size:255" json:"description"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gorm.io/driver/mysql"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
// "strconv"
|
||||
)
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
func InitDB() error {
|
||||
var err error
|
||||
dsn := config.AppConfig.DB.DSN()
|
||||
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.AutoMigrate(&models.Permission{}, &models.Role{}, &models.UserGroup{}, &models.User{})
|
||||
// BaseRepository 提供基础CRUD操作
|
||||
type BaseRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewBaseRepository(db *gorm.DB) *BaseRepository {
|
||||
return &BaseRepository{db: db}
|
||||
}
|
||||
|
||||
// 事务支持
|
||||
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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func GetPermissionByID(id uint) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
result := db.First(&permission, id)
|
||||
return &permission, result.Error
|
||||
type PermissionRepository interface {
|
||||
Create(permission *models.Permission) error
|
||||
Update(permission *models.Permission) 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) {
|
||||
var permissions []models.Permission
|
||||
result := db.Find(&permissions)
|
||||
return permissions, result.Error
|
||||
type permissionRepository struct {
|
||||
*BaseRepository
|
||||
}
|
||||
|
||||
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
|
||||
func NewPermissionRepository(db *gorm.DB) PermissionRepository {
|
||||
return &permissionRepository{
|
||||
BaseRepository: NewBaseRepository(db),
|
||||
}
|
||||
return GetPermissionByID(id)
|
||||
}
|
||||
|
||||
func CreatePermission(permission *models.Permission) (*models.Permission, error) {
|
||||
result := db.Create(permission)
|
||||
return permission, result.Error
|
||||
func (r *permissionRepository) Create(permission *models.Permission) error {
|
||||
return r.BaseRepository.Create(permission)
|
||||
}
|
||||
|
||||
func DeletePermission(id uint) error {
|
||||
result := db.Delete(&models.Permission{}, id)
|
||||
return result.Error
|
||||
func (r *permissionRepository) Update(permission *models.Permission) error {
|
||||
return r.BaseRepository.Update(permission)
|
||||
}
|
||||
|
||||
func CheckPermissionExists(name string) (bool, error) {
|
||||
var count int64
|
||||
result := db.Model(&models.Permission{}).Where("name = ?", name).Count(&count)
|
||||
return count > 0, result.Error
|
||||
func (r *permissionRepository) Delete(permission *models.Permission) error {
|
||||
return r.BaseRepository.Delete(permission)
|
||||
}
|
||||
|
||||
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 (r *permissionRepository) FindByID(id uint) (*models.Permission, error) {
|
||||
var permission models.Permission
|
||||
err := r.BaseRepository.FindByID(&permission, id)
|
||||
return &permission, err
|
||||
}
|
||||
|
||||
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)
|
||||
func (r *permissionRepository) FindAll() ([]models.Permission, error) {
|
||||
var permissions []models.Permission
|
||||
err := r.BaseRepository.FindAll(&permissions)
|
||||
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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateRole(role *models.Role) (*models.Role, error) {
|
||||
result := db.Create(role)
|
||||
return role, result.Error
|
||||
type RoleRepository struct {
|
||||
*BaseRepository
|
||||
}
|
||||
|
||||
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.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
|
||||
func NewRoleRepository(db *gorm.DB) *RoleRepository {
|
||||
return &RoleRepository{
|
||||
BaseRepository: NewBaseRepository(db),
|
||||
}
|
||||
return GetRoleByID(id)
|
||||
}
|
||||
|
||||
func DeleteRole(id uint) error {
|
||||
result := db.Delete(&models.Role{}, id)
|
||||
return result.Error
|
||||
// 根据角色名称查找角色
|
||||
func (r *RoleRepository) FindByName(role *models.Role, name string) 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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
// "gorm.io/gorm"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
for _, role := range user.Roles {
|
||||
for _, perm := range role.Permissions {
|
||||
if perm.Name == permission {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
result := db.Find(&users)
|
||||
return users, result.Error
|
||||
err := r.BaseRepository.FindAll(&users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
func GetUserByID(id string) (*models.User, error) {
|
||||
func (r *userRepository) FindByUsername(username string) (*models.User, error) {
|
||||
var user models.User
|
||||
result := db.First(&user, "id = ?", id)
|
||||
return &user, result.Error
|
||||
err := r.db.Where("username = ?", username).First(&user).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) {
|
||||
var user models.User
|
||||
result := db.First(&user, "username = ?", username)
|
||||
return &user, result.Error
|
||||
type userRepository struct {
|
||||
*BaseRepository
|
||||
}
|
||||
|
||||
func CreateUser(user *models.User) (*models.User, error) {
|
||||
result := db.Create(user)
|
||||
return user, result.Error
|
||||
}
|
||||
|
||||
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
|
||||
func NewUserRepository(db *gorm.DB) UserRepository {
|
||||
return &userRepository{
|
||||
BaseRepository: NewBaseRepository(db),
|
||||
}
|
||||
return GetUserByID(id)
|
||||
}
|
||||
|
||||
func DeleteUser(id string) error {
|
||||
result := db.Delete(&models.User{}, "id = ?", id)
|
||||
return result.Error
|
||||
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.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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateUserGroup(userGroup *models.UserGroup) (*models.UserGroup, error) {
|
||||
result := db.Create(userGroup)
|
||||
return userGroup, result.Error
|
||||
type UserGroupRepository interface {
|
||||
Create(group *models.UserGroup) 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) {
|
||||
var userGroup models.UserGroup
|
||||
result := db.Preload("Users").Preload("Roles").First(&userGroup, id)
|
||||
return &userGroup, result.Error
|
||||
type userGroupRepository struct {
|
||||
*BaseRepository
|
||||
}
|
||||
|
||||
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
|
||||
func NewUserGroupRepository(db *gorm.DB) UserGroupRepository {
|
||||
return &userGroupRepository{
|
||||
BaseRepository: NewBaseRepository(db),
|
||||
}
|
||||
return GetUserGroupByID(id)
|
||||
}
|
||||
|
||||
func DeleteUserGroup(id uint) error {
|
||||
result := db.Delete(&models.UserGroup{}, id)
|
||||
return result.Error
|
||||
func (r *userGroupRepository) Create(group *models.UserGroup) error {
|
||||
return r.BaseRepository.Create(group)
|
||||
}
|
||||
|
||||
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 (r *userGroupRepository) Update(group *models.UserGroup) error {
|
||||
return r.BaseRepository.Update(group)
|
||||
}
|
||||
|
||||
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 (r *userGroupRepository) Delete(group *models.UserGroup) error {
|
||||
return r.BaseRepository.Delete(group)
|
||||
}
|
||||
|
||||
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 (r *userGroupRepository) FindByID(id uint) (*models.UserGroup, error) {
|
||||
var group models.UserGroup
|
||||
err := r.BaseRepository.FindByID(&group, id)
|
||||
return &group, err
|
||||
}
|
||||
|
||||
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}})
|
||||
func (r *userGroupRepository) FindAll() ([]models.UserGroup, error) {
|
||||
var groups []models.UserGroup
|
||||
err := r.BaseRepository.FindAll(&groups)
|
||||
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
|
||||
|
||||
import (
|
||||
"gitea.zjmud.xyz/phyer/rbac/api"
|
||||
// "gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
// "gorm.io/driver/mysql"
|
||||
// "gorm.io/gorm"
|
||||
)
|
||||
|
||||
// InitDB is now handled in repositories package
|
||||
|
||||
// NewServer creates and returns a new Gin server
|
||||
func NewServer() *gin.Engine {
|
||||
r := gin.Default()
|
||||
return r
|
||||
}
|
||||
|
||||
func Start() {
|
||||
r := gin.Default()
|
||||
|
||||
// 初始化路由
|
||||
api.SetupRoutes(r)
|
||||
|
||||
// 启动服务器
|
||||
r.Run(":8080")
|
||||
func StartServer(router *gin.Engine, cfg *config.Config) {
|
||||
addr := fmt.Sprintf(":%s", cfg.ServerPort)
|
||||
fmt.Printf("Starting server on %s\n", addr)
|
||||
if err := router.Run(addr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,31 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
// "gitea.zjmud.xyz/phyer/rbac/models"
|
||||
"strconv"
|
||||
|
||||
"gitea.zjmud.xyz/phyer/rbac/repositories"
|
||||
"gitea.zjmud.xyz/phyer/rbac/utils"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gitea.zjmud.com/phyer/rbac/models"
|
||||
"gitea.zjmud.com/phyer/rbac/repositories"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Login(username, password string) (string, error) {
|
||||
user, err := repositories.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
return "", errors.New("invalid credentials")
|
||||
}
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||
if err != nil {
|
||||
return "", errors.New("invalid credentials")
|
||||
}
|
||||
token, err := utils.GenerateJWT(strconv.FormatUint(uint64(user.ID), 10))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return token, nil
|
||||
type AuthService struct {
|
||||
userRepo repositories.UserRepository
|
||||
}
|
||||
|
||||
func NewAuthService(db *gorm.DB) *AuthService {
|
||||
return &AuthService{
|
||||
userRepo: repositories.NewUserRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AuthService) Authenticate(username, password string) (*models.User, error) {
|
||||
user, err := s.userRepo.FindByUsername(username)
|
||||
if err != 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
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gitea.zjmud.xyz/phyer/rbac/config"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func GenerateJWT(userID string) (string, error) {
|
||||
claims := jwt.MapClaims{
|
||||
"user_id": userID,
|
||||
"exp": time.Now().Add(time.Hour * 24).Unix(),
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return token.SignedString([]byte(config.AppConfig.JWTSecret))
|
||||
var JWTSecret = []byte("your-secret-key")
|
||||
|
||||
type Claims struct {
|
||||
UserID uint `json:"user_id"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func ParseJWT(tokenString string) (jwt.MapClaims, error) {
|
||||
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(config.AppConfig.JWTSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func GenerateToken(userID uint) (string, error) {
|
||||
expirationTime := time.Now().Add(24 * time.Hour)
|
||||
claims := &Claims{
|
||||
UserID: userID,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
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 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
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
// SuccessResponse 成功响应结构
|
||||
type SuccessResponse struct {
|
||||
type Response 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,
|
||||
func Success(c *gin.Context, data interface{}) {
|
||||
c.JSON(200, Response{
|
||||
Code: 200,
|
||||
Message: "success",
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// RespondError 返回错误响应
|
||||
func RespondError(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, ErrorResponse{
|
||||
func Error(c *gin.Context, code int, message string) {
|
||||
c.JSON(code, Response{
|
||||
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,
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user