374 lines
8.6 KiB
Go
374 lines
8.6 KiB
Go
// 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)
|
||
}
|
||
}
|