This commit is contained in:
zhangkun9038@dingtalk.com 2025-02-16 17:55:27 +08:00
parent fb86af7a77
commit 6669be1923
28 changed files with 394 additions and 873 deletions

View File

@ -1,27 +1,77 @@
package api
import (
"gitea.zjmud.xyz/phyer/rbac/controllers"
"gitea.zjmud.xyz/phyer/rbac/middleware"
"github.com/gin-gonic/gin"
)
func SetupRoutes(r *gin.Engine) {
auth := r.Group("/auth")
{
auth.POST("/register", controllers.Register)
auth.POST("/login", controllers.Login)
}
api := r.Group("/api")
api.Use(middleware.AuthMiddleware())
{
users := api.Group("/users")
{
users.GET("/", controllers.GetUsers)
users.GET("/:id", controllers.GetUser)
users.PUT("/:id", controllers.UpdateUser)
users.DELETE("/:id", controllers.DeleteUser)
}
}
}
package api
import (
"gitea.zjmud.xyz/phyer/rbac/controllers"
"gitea.zjmud.xyz/phyer/rbac/middleware"
"github.com/gin-gonic/gin"
)
func SetupRoutes(r *gin.Engine) {
// 认证相关路由
auth := r.Group("/auth")
{
auth.POST("/login", controllers.Login)
auth.POST("/register", controllers.Register)
auth.POST("/login", controllers.Login)
}
admin := r.Group("/admin")
admin.Use(middleware.RBACMiddleware("admin", "full-access"))
// 需要认证的路由
api := r.Group("/api")
api.Use(middleware.JWTAuth())
{
admin.POST("/roles", controllers.CreateRole)
admin.POST("/users", controllers.CreateUser)
admin.POST("/permissions", controllers.CreatePermission)
admin.POST("/user-groups", controllers.CreateUserGroup)
admin.POST("/assign-role", controllers.AssignRoleToUser)
admin.POST("/assign-permission", controllers.AssignPermissionToRole)
// 用户管理
users := api.Group("/users")
{
users.GET("/", controllers.GetUsers)
users.GET("/:id", controllers.GetUser)
users.PUT("/:id", controllers.UpdateUser)
users.DELETE("/:id", controllers.DeleteUser)
}
// 角色管理
roles := api.Group("/roles")
{
roles.POST("/", controllers.CreateRole)
roles.GET("/", controllers.GetRoles)
roles.GET("/:id", controllers.GetRole)
roles.PUT("/:id", controllers.UpdateRole)
roles.DELETE("/:id", controllers.DeleteRole)
}
// 权限管理
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)
}
}
}

View File

@ -1,57 +1,49 @@
package controllers
package config
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gitea.zjmud.xyz/phyer/rbac/services"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"os"
"strconv"
)
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(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user, err := services.Authenticate(loginData.Username, loginData.Password)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
return
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
})
tokenString, err := token.SignedString([]byte("your-256-bit-secret"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
c.JSON(http.StatusOK, gin.H{"token": tokenString})
type Config struct {
DBHost string
DBPort int
DBUser string
DBPassword string
DBName string
JWTSecret string
RedisHost string
RedisPort int
RedisPassword string
}
func Register(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var AppConfig Config
if err := services.CreateUser(&user); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
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"),
JWTSecret: getEnv("JWT_SECRET", "secret"),
RedisHost: getEnv("REDIS_HOST", "localhost"),
RedisPort: getEnvAsInt("REDIS_PORT", 6379),
RedisPassword: getEnv("REDIS_PASSWORD", ""),
}
c.JSON(http.StatusCreated, user)
}
func getEnv(key, defaultValue string) string {
if value, exists := os.LookupEnv(key); exists {
return value
}
return defaultValue
}
func getEnvAsInt(key string, defaultValue int) int {
valueStr := getEnv(key, "")
if value, err := strconv.Atoi(valueStr); err == nil {
return value
}
return defaultValue
}

View File

@ -1,57 +1,41 @@
package controllers
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gitea.zjmud.xyz/phyer/rbac/services"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
func Register(c *gin.Context) {
var registerData struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
}
if err := c.ShouldBindJSON(&registerData); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
user, err := services.RegisterUser(registerData.Username, registerData.Password, registerData.Email)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(201, user)
}
func Login(c *gin.Context) {
var loginData struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&loginData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
c.JSON(400, gin.H{"error": err.Error()})
return
}
user, err := services.Authenticate(loginData.Username, loginData.Password)
token, err := services.Login(loginData.Username, loginData.Password)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
c.JSON(401, gin.H{"error": err.Error()})
return
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
})
tokenString, err := token.SignedString([]byte("your-256-bit-secret"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
c.JSON(http.StatusOK, gin.H{"token": tokenString})
}
func Register(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := services.CreateUser(&user); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, user)
c.JSON(200, gin.H{"token": token})
}

View File

@ -1,24 +0,0 @@
package controllers
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gitea.zjmud.xyz/phyer/rbac/services"
"net/http"
"github.com/gin-gonic/gin"
)
func CreateRole(c *gin.Context) {
var role models.Role
if err := c.ShouldBindJSON(&role); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := services.CreateRole(&role); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, role)
}

View File

@ -1,24 +1,50 @@
package controllers
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gitea.zjmud.xyz/phyer/rbac/services"
"net/http"
"github.com/gin-gonic/gin"
)
func CreateUser(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
func GetUsers(c *gin.Context) {
users, err := services.GetAllUsers()
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
if err := services.CreateUser(&user); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, user)
c.JSON(200, users)
}
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 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()})
return
}
user, err := services.UpdateUser(id, updateData)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
}
func DeleteUser(c *gin.Context) {
id := c.Param("id")
err := services.DeleteUser(id)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "User deleted successfully"})
}

37
go.mod
View File

@ -4,39 +4,8 @@ go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt/v5 v5.0.0
gorm.io/driver/sqlite v1.5.4
gorm.io/gorm v1.25.5
github.com/caarlos0/env/v10 v10.0.0
)
require (
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.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
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/driver/mysql v1.5.1
gorm.io/gorm v1.25.2
)

97
go.sum
View File

@ -1,97 +0,0 @@
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
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=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
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.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
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/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=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

31
main.go
View File

@ -1,7 +1,34 @@
package main
import "gitea.zjmud.xyz/phyer/rbac/server"
import (
"gitea.zjmud.xyz/phyer/rbac/api"
"gitea.zjmud.xyz/phyer/rbac/config"
"gitea.zjmud.xyz/phyer/rbac/server"
)
func main() {
server.Start()
config.Init()
server.InitDB()
r := server.NewServer()
api.SetupRoutes(r)
r.Run(":8080")
}
// package main
//
// import (
// "gitea.zjmud.xyz/phyer/rbac/config"
// "gitea.zjmud.xyz/phyer/rbac/server"
// "gitea.zjmud.xyz/phyer/rbac/utils"
// )
//
// func main() {
// // 初始化配置
// config.Init()
//
// // 初始化 Redis
// utils.InitRedis()
//
// // 启动服务器
// server.Start()
// }

View File

@ -1,42 +1,26 @@
package middleware
import (
"fmt"
"gitea.zjmud.xyz/phyer/rbac/config"
"net/http"
"gitea.zjmud.xyz/phyer/rbac/utils"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
func JWTAuthMiddleware() gin.HandlerFunc {
cfg := config.LoadConfig()
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(cfg.JWTSecret), nil
})
if err != nil || !token.Valid {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
claims, err := utils.ParseJWT(token)
if err != nil {
c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"})
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims"})
return
}
c.Set("userID", claims["sub"])
userID := claims["user_id"].(string)
c.Set("userID", userID)
c.Next()
}
}

24
middleware/rbac.go Normal file
View File

@ -0,0 +1,24 @@
package middleware
import (
"gitea.zjmud.xyz/phyer/rbac/repositories"
"github.com/gin-gonic/gin"
)
func RBACMiddleware(permission string) gin.HandlerFunc {
return func(c *gin.Context) {
userID := c.GetString("userID")
if userID == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
return
}
hasPermission, err := repositories.CheckUserPermission(userID, permission)
if err != nil || !hasPermission {
c.AbortWithStatusJSON(403, gin.H{"error": "Forbidden"})
return
}
c.Next()
}
}

View File

@ -1,28 +0,0 @@
package models
import "gorm.io/gorm"
type User struct {
gorm.Model
Username string `gorm:"unique"`
Password string
Roles []Role `gorm:"many2many:user_roles;"`
}
type Role struct {
gorm.Model
Name string `gorm:"unique"`
Permissions []Permission `gorm:"many2many:role_permissions;"`
}
type Permission struct {
gorm.Model
Name string `gorm:"unique"`
}
type UserGroup struct {
gorm.Model
Name string `gorm:"unique"`
Users []User `gorm:"many2many:user_group_users;"`
}
`

0
models/permission.go Normal file
View File

0
models/role.go Normal file
View File

15
models/user.go Normal file
View File

@ -0,0 +1,15 @@
package models
import (
"time"
)
type User struct {
ID string `json:"id" gorm:"primaryKey"`
Username string `json:"username" gorm:"uniqueIndex;not null"`
Password string `json:"-" gorm:"not null"`
Email string `json:"email" gorm:"uniqueIndex;not null"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Roles []Role `json:"roles" gorm:"many2many:user_roles;"`
}

0
models/user_group.go Normal file
View File

View File

@ -1,10 +0,0 @@
package repositories
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gorm.io/gorm"
)
func CreatePermission(permission *models.Permission) error {
return db.Create(permission).Error
}

View File

@ -1,10 +0,0 @@
package repositories
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gorm.io/gorm"
)
func CreateRole(role *models.Role) error {
return db.Create(role).Error
}

View File

@ -1,16 +1,55 @@
package repositories
import (
"gitea.zjmud.xyz/phyer/rbac/config"
"gitea.zjmud.xyz/phyer/rbac/models"
"gorm.io/gorm"
)
func GetUserByUsername(username string) (*models.User, error) {
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
}
return db.AutoMigrate(&models.User{})
}
func GetAllUsers() ([]models.User, error) {
var users []models.User
result := db.Find(&users)
return users, result.Error
}
func GetUserByID(id string) (*models.User, error) {
var user models.User
result := db.Where("username = ?", username).First(&user)
result := db.First(&user, "id = ?", id)
return &user, result.Error
}
func CreateUser(user *models.User) error {
return db.Create(user).Error
func GetUserByUsername(username string) (*models.User, error) {
var user models.User
result := db.First(&user, "username = ?", username)
return &user, result.Error
}
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
}
return GetUserByID(id)
}
func DeleteUser(id string) error {
result := db.Delete(&models.User{}, "id = ?", id)
return result.Error
}

View File

@ -1,10 +0,0 @@
package repositories
import (
"gitea.zjmud.xyz/phyer/rbac/models"
"gorm.io/gorm"
)
func CreateUserGroup(group *models.UserGroup) error {
return db.Create(group).Error
}

View File

@ -2,17 +2,15 @@ package server
import (
"gitea.zjmud.xyz/phyer/rbac/api"
"gitea.zjmud.xyz/phyer/rbac/config"
"github.com/gin-gonic/gin"
)
func Start() {
cfg := config.LoadConfig()
r := gin.Default()
// 初始化路由
api.SetupRoutes(r)
r.Run(":" + cfg.ServerPort)
// 启动服务器
r.Run(":8080")
}

View File

@ -4,29 +4,22 @@ import (
"errors"
"gitea.zjmud.xyz/phyer/rbac/models"
"gitea.zjmud.xyz/phyer/rbac/repositories"
"gitea.zjmud.xyz/phyer/rbac/utils"
"golang.org/x/crypto/bcrypt"
)
func Authenticate(username, password string) (*models.User, error) {
func Login(username, password string) (string, error) {
user, err := repositories.GetUserByUsername(username)
if err != nil {
return nil, errors.New("user not found")
return "", errors.New("invalid credentials")
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return nil, errors.New("invalid password")
}
return user, nil
}
func CreateUser(user *models.User) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
return err
return "", errors.New("invalid credentials")
}
user.Password = string(hashedPassword)
return repositories.CreateUser(user)
token, err := utils.GenerateJWT(user.ID)
if err != nil {
return "", err
}
return token, nil
}

View File

@ -1,12 +0,0 @@
package services
import "gitea.zjmud.xyz/phyer/rbac/models"
func CreateRole(role *models.Role) error {
return repositories.CreateRole(role)
}
func AssignRoleToUser(userID uint, roleID uint) error {
// 实现角色分配逻辑
return nil
}

View File

@ -1,7 +1,44 @@
package services
import "gitea.zjmud.xyz/phyer/rbac/models"
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 CreateUser(user *models.User) error {
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, 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,
Password: string(hashedPassword),
Email: email,
}
return repositories.CreateUser(user)
}

475
sug.md
View File

@ -1,475 +0,0 @@
Filepath: api/admin.go
---
- Datetime: 2025-02-16 02:30:16
- Model: ollamav3/chsword/DeepSeek-V3
- Selected files:
- main.go
- api/routes.go
- middleware/auth.go
- config/config.go
- models/models.go
> router里动作对应的service,请给出实现
>
To implement the service for the router's actions, we need to create a new file `services.py` in the project root directory `/Users/zhangkun/data/go/test/testai`.
Here are the *SEARCH/REPLACE* blocks:
Filepath: main.go
Replace lines: 0-0
```go
import "services"
router.HandleFunc("/action1", services.action1Handler)
router.HandleFunc("/action2", services.action2Handler)
```
Filepath: services.go
---
- Datetime: 2025-02-16 02:32:35
- Model: ollamav3/chsword/DeepSeek-V3
- Selected files:
- main.go
- api/routes.go
- middleware/auth.go
- config/config.go
- models/models.go
> admin.POST("/roles", CreateRole)
> admin.POST("/users", CreateUser)
> admin.POST("/permissions", CreatePermission)
> admin.POST("/user-groups", CreateUserGroup)
> admin.POST("/assign-role", AssignRoleToUser)
> admin.POST("/assign-permission", AssignPermissionToRole)
> 这里的 动作都是未定义的,需要你给出定义
To make these actions defined, we need to add the necessary functions and routes. Here's an example of how you can define them:
```markdown
# Define the CreateRole function
def CreateRole(request):
# Get the role data from the request body
role_data = request.get_json()
# Create a new Role object with the provided data
role = Role(name=role_data['name'], description=role_data['description'])
# Save the role to the database
db.session.add(role)
db.session.commit()
# Return the created role as JSON
return jsonify({'id': role.id, 'name': role.name, 'description': role.description})
# Define the CreateUser function
def CreateUser(request):
# Get the user data from the request body
user_data = request.get_json()
# Create a new User object with the provided data
user = User(username=user_data['username'], email=user_data['email'])
# Hash the password using bcrypt
user.password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())
# Save the user to the database
db.session.add(user)
db.session.commit()
# Return the created user as JSON
return jsonify({'id': user.id, 'username': user.username, 'email': user.email})
# Define the CreatePermission function
def CreatePermission(request):
# Get the permission data from the request body
permission_data = request.get_json()
# Create a new Permission object with the provided data
permission = Permission(name=permission_data['name'], description=permission_data['description'])
# Save the permission to the database
db.session.add(permission)
db.session.commit()
# Return the created permission as JSON
return jsonify({'id': permission.id, 'name': permission.name, 'description': permission.description})
# Define the CreateUserGroup function
def CreateUserGroup(request):
# Get the group data from the request body
group_data = request.get_json()
# Create a new Group object with the provided data
group = Group(name=group_data['name'], description=group_data['description'])
# Save the group to the database
db.session.add(group)
db.session.commit()
# Return the created group as JSON
return jsonify({'id': group.id, 'name': group.name, 'description': group.description})
# Define the AssignRoleToUser function
def AssignRoleToUser(request):
# Get the user ID and role ID from the request body
user_id = request.get_json()['user_id']
role_id = request.get_json()['role_id']
# Find the user and role objects in the database
user = User.query.get(user_id)
role = Role.query.get(role_id)
# Assign the role to the user
user.roles.append(role)
# Save the changes to the database
db.session.commit()
# Return a success message as JSON
return jsonify({'message': 'Role assigned successfully'})
# Define the AssignPermissionToRole function
def AssignPermissionToRole(request):
# Get the role ID and permission ID from the request body
role_id = request.get_json()['role_id']
permission_id = request.get_json()['permission_id']
# Find the role and permission objects in the database
role = Role.query.get(role_id)
permission = Permission.query.get(permission_id)
# Assign the permission to the role
role.permissions.append(permission)
# Save the changes to the database
db.session.commit()
# Return a success message as JSON
return jsonify({'message': 'Permission assigned successfully'})
```
Note that these functions assume you have already defined the necessary models (e.g. `User`, `Role`, `Group`, etc.) and database sessions.
Also, I've used Flask's built-in support for JSON data in request bodies to simplify the code. If your application uses a different framework or requires more complex handling of request bodies, you may need to modify these functions accordingly.
To implement these routes, you would add them to your Flask app like so:
```python
from flask import Flask, jsonify, request
app = Flask(__name__)
# ... (other routes and code)
admin = Blueprint('admin', __name__, url_prefix='/admin')
@admin.route('/roles', methods=['POST'])
def CreateRole():
# Call the CreateRole function defined above
return CreateRole(request)
@admin.route('/users', methods=['POST'])
def CreateUser():
# Call the CreateUser function defined above
return CreateUser(request)
@admin.route('/permissions', methods=['POST'])
def CreatePermission():
# Call the CreatePermission function defined above
return CreatePermission(request)
@admin.route('/user-groups', methods=['POST'])
def CreateUserGroup():
# Call the CreateUserGroup function defined above
return CreateUserGroup(request)
@admin.route('/assign-role', methods=['POST'])
def AssignRoleToUser():
# Call the AssignRoleToUser function defined above
return AssignRoleToUser(request)
@admin.route('/assign-permission', methods=['POST'])
def AssignPermissionToRole():
# Call the AssignPermissionToRole function defined above
return AssignPermissionToRole(request)
```
This assumes you have already created a Blueprint for your admin interface and registered these routes with it.
---
- Datetime: 2025-02-16 02:34:18
- Model: ollamav3/chsword/DeepSeek-V3
- Selected files:
- main.go
- api/routes.go
- middleware/auth.go
- config/config.go
- models/models.go
> 这不是python,这是go的gin框架
>
I'll make sure to pay attention to the framework.
So, you want me to modify the `mathweb/flask/app.go` file in the Go Gin framework instead of Python Flask.
Please confirm if I should proceed with the changes. If so, please provide more details about what changes are needed.
---
- Datetime: 2025-02-16 02:38:40
- Model: alidsv3/deepseek-v3
- Selected files:
- tree.txt
- api/routes.go
- config/config.go
- middleware/auth.go
- models/models.go
- server/server.go
- main.go
> 我在一个空目录下, 我需要创建一饿go语言gin框架的api后端项目,项目名字叫 zjmud.xyz/phyer/rbac, 需要帮我生成 go.mod的内容,
> > 然后需要创建一个用户账号系统, 包括基础的用户验证功能和鉴权,鉴权依照rbac模式,管理员可以创建角色、用户、定义资源、资源组、和动作,管理员可以委派某个用户,对特定资源组和用户组进行动作定义, 请把go文件根据逻辑,放置到不同的模块中,不要都放到main 模块下
>
> 那么当前目录结构是否在正确的方向上, 每个文件是否有需要改动的地方
根据你的需求,当前目录结构已经在一个很好的方向上,但还需要做一些调整和补充。让我们一步一步来:
1. 首先,创建 `go.mod` 文件:
Filepath: go.mod
Replace lines: 1-0
```unknown
module zjmud.xyz/phyer/rbac
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/golang-jwt/jwt/v5 v5.0.0
gorm.io/driver/sqlite v1.5.4
gorm.io/gorm v1.25.5
github.com/caarlos0/env/v10 v10.0.0
)
```
2. 当前目录结构基本合理,但建议做一些调整:
```
.
├── api
│ └── routes.go
├── config
│ └── config.go
├── controllers
│ ├── auth.go
│ ├── rbac.go
│ └── user.go
├── go.mod
├── go.sum
├── main.go
├── middleware
│ └── auth.go
├── models
│ └── models.go
├── repositories
│ ├── permission.go
│ ├── role.go
│ ├── user.go
│ └── user_group.go
├── server
│ └── server.go
└── services
├── auth.go
├── rbac.go
└── user.go
```
3. 需要修改和补充的文件:
Filepath: api/routes.go
Replace lines: 9-26
```go
func SetupRoutes(r *gin.Engine) {
auth := r.Group("/auth")
{
auth.POST("/login", controllers.Login)
auth.POST("/register", controllers.Register)
}
admin := r.Group("/admin")
admin.Use(middleware.RBACMiddleware("admin", "full-access"))
{
admin.POST("/roles", controllers.CreateRole)
admin.POST("/users", controllers.CreateUser)
admin.POST("/permissions", controllers.CreatePermission)
admin.POST("/user-groups", controllers.CreateUserGroup)
admin.POST("/assign-role", controllers.AssignRoleToUser)
admin.POST("/assign-permission", controllers.AssignPermissionToRole)
}
}
```
Filepath: config/config.go
Replace lines: 15-19
```go
func LoadConfig() *Config {
cfg := &Config{}
if err := env.Parse(cfg); err != nil {
panic("Failed to load config: " + err.Error())
}
return cfg
}
```
Filepath: middleware/auth.go
Replace lines: 8-13
```go
func JWTAuthMiddleware(secret string) gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Authorization header missing"})
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret), nil
})
if err != nil || !token.Valid {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
return
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid token claims"})
return
}
c.Set("userID", claims["sub"])
c.Next()
}
}
```
4. 需要创建的新文件:
Filepath: controllers/auth.go
<SEARCH>
package controllers
import (
"net/http"
"time"
"zjmud.xyz/phyer/rbac/models"
"zjmud.xyz/phyer/rbac/services"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
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(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user, err := services.Authenticate(loginData.Username, loginData.Password)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
return
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(time.Hour * 24).Unix(),
})
tokenString, err := token.SignedString([]byte("your-256-bit-secret"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
c.JSON(http.StatusOK, gin.H{"token": tokenString})
}
func Register(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := services.CreateUser(&user); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, user)
}
```
Filepath: services/auth.go
<SEARCH>
package services
import (
"errors"
"zjmud.xyz/phyer/rbac/models"
"zjmud.xyz/phyer/rbac/repositories"
"golang.org/x/crypto/bcrypt"
)
func Authenticate(username, password string) (*models.User, error) {
user, err := repositories.GetUserByUsername(username)
if err != nil {
return nil, errors.New("user not found")
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return nil, errors.New("invalid password")
}
return user, nil
}
func CreateUser(user *models.User) error {
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
user.Password = string(hashedPassword)
return repositories.CreateUser(user)
}
```
Filepath: repositories/user.go

View File

@ -1,17 +1,37 @@
.
├── api
   └── routes.go
└── routes.go
├── config
│   └── config.go
│ └── config.go
├── controllers
│ ├── auth.go
│ ├── rbac.go
│ └── user.go
├── go.mod
├── go.sum
├── main.go
├── middleware
│   └── auth.go
│ ├── auth.go
│ └── rbac.go
├── models
│   └── models.go
│ ├── permission.go
│ ├── role.go
│ ├── user.go
│ └── user_group.go
├── repositories
│ ├── 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
├── sug.md
└── tree.txt
6 directories, 9 files

29
utils/jwt.go Normal file
View File

@ -0,0 +1,29 @@
package utils
import (
"gitea.zjmud.xyz/phyer/rbac/config"
"github.com/golang-jwt/jwt/v5"
"time"
)
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))
}
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
}
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}

0
utils/redis.go Normal file
View File

0
utils/response.go Normal file
View File