This commit is contained in:
2026-10-25 22:47:13 +08:00
parent 897d6c4483
commit b34fba352b
20 changed files with 2615 additions and 0 deletions
+373
View File
@@ -0,0 +1,373 @@
// Package rbachdl 是后台 RBAC 管理(管理员 / 角色 / 权限)的 HTTP 接入层。
package rbachdl
import (
"strconv"
"github.com/gin-gonic/gin"
"portal-mini-go/internal/middleware"
"portal-mini-go/internal/pkg/errors"
"portal-mini-go/internal/pkg/response"
"portal-mini-go/internal/service/admin/rbac"
)
// Handler 聚合管理员 / 角色 / 权限三类管理接口。
type Handler struct {
adminSvc *rbac.AdminService
roleSvc *rbac.RoleService
permSvc *rbac.PermissionService
}
func NewHandler(adminSvc *rbac.AdminService, roleSvc *rbac.RoleService, permSvc *rbac.PermissionService) *Handler {
return &Handler{adminSvc: adminSvc, roleSvc: roleSvc, permSvc: permSvc}
}
// ---- 管理员 ----
// CreateAdmin 新建管理员。
func (h *Handler) CreateAdmin(c *gin.Context) {
var req rbac.CreateAdminReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
u, err := h.adminSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// ListAdmins 分页查询管理员。支持 query:keyword、status、page、size。
func (h *Handler) ListAdmins(c *gin.Context) {
keyword := c.Query("keyword")
status, _ := strconv.ParseInt(c.DefaultQuery("status", "-1"), 10, 8)
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.adminSvc.List(c.Request.Context(), rbac.AdminListReq{
Keyword: keyword,
Status: int8(status),
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// GetAdmin 查询单个管理员。
func (h *Handler) GetAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
u, err := h.adminSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// UpdateAdmin 编辑管理员昵称 / 状态。
func (h *Handler) UpdateAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdateAdminReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
u, err := h.adminSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, u)
}
// DeleteAdmin 删除管理员。
func (h *Handler) DeleteAdmin(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.adminSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// AssignAdminRoles 为管理员分配角色。
func (h *Handler) AssignAdminRoles(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
RoleIDs []uint64 `json:"role_ids" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.adminSvc.SetRoles(c.Request.Context(), id, req.RoleIDs); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ResetAdminPassword 重置管理员密码。
func (h *Handler) ResetAdminPassword(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.adminSvc.ResetPassword(c.Request.Context(), id, req.Password); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ---- 角色 ----
// CreateRole 新建角色。
func (h *Handler) CreateRole(c *gin.Context) {
var req rbac.CreateRoleReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
r, err := h.roleSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// ListRoles 分页查询角色。支持 query:keyword、status、page、size。
func (h *Handler) ListRoles(c *gin.Context) {
keyword := c.Query("keyword")
status, _ := strconv.ParseInt(c.DefaultQuery("status", "-1"), 10, 8)
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.roleSvc.List(c.Request.Context(), rbac.RoleListReq{
Keyword: keyword,
Status: int8(status),
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// GetRole 查询单个角色。
func (h *Handler) GetRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
r, err := h.roleSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// UpdateRole 编辑角色。
func (h *Handler) UpdateRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdateRoleReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
r, err := h.roleSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, r)
}
// DeleteRole 删除角色。
func (h *Handler) DeleteRole(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.roleSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// AssignRolePermissions 为角色分配权限。
func (h *Handler) AssignRolePermissions(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req struct {
PermissionIDs []uint64 `json:"permission_ids" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
if err := h.roleSvc.SetPermissions(c.Request.Context(), id, req.PermissionIDs); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
// ---- 权限 ----
// ListPermissions 分页查询权限。支持 query:type(api/menu)、keyword、page、size。
func (h *Handler) ListPermissions(c *gin.Context) {
permType := c.Query("type")
keyword := c.Query("keyword")
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
list, total, err := h.permSvc.List(c.Request.Context(), rbac.PermListReq{
Type: permType,
Keyword: keyword,
Page: page,
Size: size,
})
if err != nil {
c.Error(err)
return
}
response.OK(c, gin.H{"list": list, "total": total, "page": page, "size": size})
}
// CreatePermission 新建权限。
func (h *Handler) CreatePermission(c *gin.Context) {
var req rbac.CreatePermReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
p, err := h.permSvc.Create(c.Request.Context(), req)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// GetPermission 查询单个权限。
func (h *Handler) GetPermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
p, err := h.permSvc.GetByID(c.Request.Context(), id)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// UpdatePermission 编辑权限。
func (h *Handler) UpdatePermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
var req rbac.UpdatePermReq
if err := c.ShouldBindJSON(&req); err != nil {
c.Error(errors.ErrBadRequest)
return
}
p, err := h.permSvc.Update(c.Request.Context(), id, req)
if err != nil {
c.Error(err)
return
}
response.OK(c, p)
}
// DeletePermission 删除权限。
func (h *Handler) DeletePermission(c *gin.Context) {
id, ok := parseID(c)
if !ok {
return
}
if err := h.permSvc.Delete(c.Request.Context(), id); err != nil {
c.Error(err)
return
}
response.OK(c, nil)
}
func parseID(c *gin.Context) (uint64, bool) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.Error(errors.ErrBadRequest)
return 0, false
}
return id, true
}
// Register 注册后台 RBAC 管理路由,各资源按权限粒度挂载守卫。
func Register(g *gin.RouterGroup, h *Handler) {
// 管理员
ag := g.Group("/rbac/admins", middleware.RequirePerm(middleware.PermAdminManage))
{
ag.POST("", h.CreateAdmin)
ag.GET("", h.ListAdmins)
ag.GET("/:id", h.GetAdmin)
ag.PUT("/:id", h.UpdateAdmin)
ag.DELETE("/:id", h.DeleteAdmin)
ag.POST("/:id/roles", h.AssignAdminRoles)
ag.POST("/:id/reset-pwd", h.ResetAdminPassword)
}
// 角色
rg := g.Group("/rbac/roles", middleware.RequirePerm(middleware.PermRoleManage))
{
rg.POST("", h.CreateRole)
rg.GET("", h.ListRoles)
rg.GET("/:id", h.GetRole)
rg.PUT("/:id", h.UpdateRole)
rg.DELETE("/:id", h.DeleteRole)
rg.POST("/:id/permissions", h.AssignRolePermissions)
}
// 权限
pg := g.Group("/rbac/permissions", middleware.RequirePerm(middleware.PermPermManage))
{
pg.POST("", h.CreatePermission)
pg.GET("", h.ListPermissions)
pg.GET("/:id", h.GetPermission)
pg.PUT("/:id", h.UpdatePermission)
pg.DELETE("/:id", h.DeletePermission)
}
}