添加默认系统管理员账号并限制唯一
This commit is contained in:
@@ -32,16 +32,15 @@ open http://localhost:3018
|
|||||||
| 后端 API | 3019 |
|
| 后端 API | 3019 |
|
||||||
| PostgreSQL | 5432 |
|
| PostgreSQL | 5432 |
|
||||||
|
|
||||||
## 创建首个系统管理员
|
## 默认系统管理员
|
||||||
|
|
||||||
系统不内置默认账号。启动后,先注册一个普通用户,再通过 SQL 将其提升为系统管理员:
|
系统启动时会自动创建一个系统管理员账号(仅当不存在时):
|
||||||
|
|
||||||
```bash
|
| 用户名 | 密码 |
|
||||||
docker compose exec db psql -U stock -d stock -c "
|
|---|---|
|
||||||
UPDATE users SET role_id = (SELECT id FROM roles WHERE name = 'system_admin')
|
| `system_admin` | `system_admin` |
|
||||||
WHERE username = '你的用户名';
|
|
||||||
"
|
整个系统只能有一个系统管理员账号,无法通过管理后台再创建或提升其他系统管理员。
|
||||||
```
|
|
||||||
|
|
||||||
## 角色说明
|
## 角色说明
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ func main() {
|
|||||||
log.Fatalf("seed roles: %v", err)
|
log.Fatalf("seed roles: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := models.SeedSystemAdmin(database); err != nil {
|
||||||
|
log.Fatalf("seed system admin: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
r := routes.Setup(cfg, database)
|
r := routes.Setup(cfg, database)
|
||||||
|
|
||||||
addr := fmt.Sprintf("0.0.0.0:%s", cfg.Port)
|
addr := fmt.Sprintf("0.0.0.0:%s", cfg.Port)
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ func (h *AdminHandler) UpdateUser(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if req.Status != "" {
|
if req.Status != "" {
|
||||||
|
if target.Role.NameEnum() == models.RoleSystemAdmin && req.Status != "active" {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能禁用系统管理员账号"})
|
||||||
|
return
|
||||||
|
}
|
||||||
updates["status"] = req.Status
|
updates["status"] = req.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +174,10 @@ func (h *AdminHandler) UpdateUser(c *gin.Context) {
|
|||||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "无效的角色"})
|
c.JSON(http.StatusBadRequest, gin.H{"success": false, "error": "无效的角色"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if target.Role.NameEnum() == models.RoleSystemAdmin && newRole != models.RoleSystemAdmin {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能修改系统管理员账号的角色"})
|
||||||
|
return
|
||||||
|
}
|
||||||
if !containsRole(allowedRolesForCreation(current.Role), newRole) || !current.Role.CanManage(newRole) {
|
if !containsRole(allowedRolesForCreation(current.Role), newRole) || !current.Role.CanManage(newRole) {
|
||||||
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "权限不足"})
|
||||||
return
|
return
|
||||||
@@ -211,6 +219,11 @@ func (h *AdminHandler) DeleteUser(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if target.Role.NameEnum() == models.RoleSystemAdmin {
|
||||||
|
c.JSON(http.StatusForbidden, gin.H{"success": false, "error": "不能删除系统管理员账号"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := h.DB.Delete(&target).Error; err != nil {
|
if err := h.DB.Delete(&target).Error; err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "error": "internal server error"})
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -118,6 +119,33 @@ func SeedRoles(db *gorm.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeedSystemAdmin 在没有 system_admin 用户时创建默认系统管理员账号。
|
||||||
|
func SeedSystemAdmin(db *gorm.DB) error {
|
||||||
|
var existing User
|
||||||
|
if err := db.Where("username = ?", "system_admin").First(&existing).Error; err == nil {
|
||||||
|
return nil
|
||||||
|
} else if err != gorm.ErrRecordNotFound {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var role Role
|
||||||
|
if err := db.Where("name = ?", RoleSystemAdmin).First(&role).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, err := bcrypt.GenerateFromPassword([]byte("system_admin"), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Create(&User{
|
||||||
|
Username: "system_admin",
|
||||||
|
PasswordHash: string(hash),
|
||||||
|
RoleID: role.ID,
|
||||||
|
Status: "active",
|
||||||
|
}).Error
|
||||||
|
}
|
||||||
|
|
||||||
func strPtr(s string) *string {
|
func strPtr(s string) *string {
|
||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user