mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-27 12:10:46 +00:00
PUT /api/v1/sys-user sits in CasbinExclude so the profile page can reach it, which means AuthCheckRole never runs for this route. The handler took the target user id from the request body, so any authenticated caller could edit another user's record - including their roleId. The route has to stay excluded: the profile page and the admin user list share this one endpoint, so removing the exclusion would break self-service editing for every non-admin role. The check therefore moves into the handler: when the target is not the caller, the request is put through Casbin explicitly. EnforceRoleFor carries the same admin short-circuit and enforcement AuthCheckRole uses, so a route that opts out of the middleware can still ask the same question. Claude-Session: https://claude.ai/code/session_01HPTAw8b8tAdFNFn8rKdPYx
484 lines
12 KiB
Go
484 lines
12 KiB
Go
package apis
|
|
|
|
import (
|
|
"errors"
|
|
"github.com/gin-gonic/gin/binding"
|
|
"go-admin/app/admin/models"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-admin-team/go-admin-core/v2/jwtauth/user"
|
|
_ "github.com/go-admin-team/go-admin-core/v2/response"
|
|
"github.com/go-admin-team/go-admin-core/v2/sdk/api"
|
|
"github.com/google/uuid"
|
|
|
|
"go-admin/app/admin/service"
|
|
"go-admin/app/admin/service/dto"
|
|
"go-admin/common/actions"
|
|
"go-admin/common/middleware"
|
|
)
|
|
|
|
type SysUser struct {
|
|
api.Api
|
|
}
|
|
|
|
// GetPage
|
|
// @Summary 列表用户信息数据
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Param username query string false "username"
|
|
// @Success 200 {string} {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/sys-user [get]
|
|
// @Security Bearer
|
|
func (e SysUser) GetPage(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserGetPageReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
//数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
|
|
list := make([]models.SysUser, 0)
|
|
var count int64
|
|
|
|
err = s.GetPage(&req, p, &list, &count)
|
|
if err != nil {
|
|
e.Error(500, err, "查询失败")
|
|
return
|
|
}
|
|
|
|
e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
|
|
}
|
|
|
|
// Get
|
|
// @Summary 获取用户
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Param userId path int true "用户编码"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/sys-user/{userId} [get]
|
|
// @Security Bearer
|
|
func (e SysUser) Get(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserById{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req, nil).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
var object models.SysUser
|
|
//数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
err = s.Get(&req, p, &object)
|
|
if err != nil {
|
|
e.Error(http.StatusUnprocessableEntity, err, "查询失败")
|
|
return
|
|
}
|
|
e.OK(object, "查询成功")
|
|
}
|
|
|
|
// Insert
|
|
// @Summary 创建用户
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Accept application/json
|
|
// @Product application/json
|
|
// @Param data body dto.SysUserInsertReq true "用户数据"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/sys-user [post]
|
|
// @Security Bearer
|
|
func (e SysUser) Insert(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserInsertReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req, binding.JSON).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
// 设置创建人
|
|
req.SetCreateBy(user.GetUserId(c))
|
|
err = s.Insert(&req)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
e.OK(req.GetId(), "创建成功")
|
|
}
|
|
|
|
// Update
|
|
// @Summary 修改用户数据
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Accept application/json
|
|
// @Product application/json
|
|
// @Param data body dto.SysUserUpdateReq true "body"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/sys-user/{userId} [put]
|
|
// @Security Bearer
|
|
func (e SysUser) Update(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserUpdateReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
callerId := user.GetUserId(c)
|
|
|
|
// This route is in CasbinExclude so the personal-center screen can edit
|
|
// the caller's own record without a policy grant (see settings.go). That
|
|
// exclusion covers the whole route, not just the caller's own record, and
|
|
// the request carries the target userId in the body - so without this
|
|
// check here, any authenticated caller could edit any other user, up to
|
|
// and including their roleId. When the target is someone else, ask Casbin
|
|
// directly for the permission AuthCheckRole skipped.
|
|
if req.UserId != callerId {
|
|
allowed, err := middleware.EnforceRoleFor(c, c.Request.URL.Path, c.Request.Method)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
if !allowed {
|
|
e.Error(http.StatusForbidden, errors.New("无权更新其他用户数据"), "对不起,您没有该接口访问权限,请联系管理员")
|
|
return
|
|
}
|
|
}
|
|
|
|
req.SetUpdateBy(callerId)
|
|
|
|
//数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
|
|
err = s.Update(&req, p, callerId)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
return
|
|
}
|
|
e.OK(req.GetId(), "更新成功")
|
|
}
|
|
|
|
// Delete
|
|
// @Summary 删除用户数据
|
|
// @Description 删除数据
|
|
// @Tags 用户
|
|
// @Param userId path int true "userId"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/sys-user/{userId} [delete]
|
|
// @Security Bearer
|
|
func (e SysUser) Delete(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserById{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req, binding.JSON).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
// 设置编辑人
|
|
req.SetUpdateBy(user.GetUserId(c))
|
|
|
|
// 数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
|
|
err = s.Remove(&req, p)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
return
|
|
}
|
|
e.OK(req.GetId(), "删除成功")
|
|
}
|
|
|
|
// InsetAvatar
|
|
// @Summary 修改头像
|
|
// @Description 获取JSON
|
|
// @Tags 个人中心
|
|
// @Accept multipart/form-data
|
|
// @Param file formData file true "file"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/user/avatar [post]
|
|
// @Security Bearer
|
|
func (e SysUser) InsetAvatar(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.UpdateSysUserAvatarReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
// 数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
form, _ := c.MultipartForm()
|
|
files := form.File["upload[]"]
|
|
guid := uuid.New().String()
|
|
filPath := "static/uploadfile/" + guid + ".jpg"
|
|
for _, file := range files {
|
|
e.Logger.Debugf("upload avatar file: %s", file.Filename)
|
|
// 上传文件至指定目录
|
|
err = c.SaveUploadedFile(file, filPath)
|
|
if err != nil {
|
|
e.Logger.Errorf("save file error, %s", err.Error())
|
|
e.Error(500, err, "")
|
|
return
|
|
}
|
|
}
|
|
req.UserId = p.UserId
|
|
req.Avatar = "/" + filPath
|
|
|
|
err = s.UpdateAvatar(&req, p)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
return
|
|
}
|
|
e.OK(filPath, "修改成功")
|
|
}
|
|
|
|
// UpdateStatus 修改用户状态
|
|
// @Summary 修改用户状态
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Accept application/json
|
|
// @Product application/json
|
|
// @Param data body dto.UpdateSysUserStatusReq true "body"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/user/status [put]
|
|
// @Security Bearer
|
|
func (e SysUser) UpdateStatus(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.UpdateSysUserStatusReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req, binding.JSON, nil).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
req.SetUpdateBy(user.GetUserId(c))
|
|
|
|
//数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
|
|
err = s.UpdateStatus(&req, p)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
return
|
|
}
|
|
e.OK(req.GetId(), "更新成功")
|
|
}
|
|
|
|
// ResetPwd 重置用户密码
|
|
// @Summary 重置用户密码
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Accept application/json
|
|
// @Product application/json
|
|
// @Param data body dto.ResetSysUserPwdReq true "body"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/user/pwd/reset [put]
|
|
// @Security Bearer
|
|
func (e SysUser) ResetPwd(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.ResetSysUserPwdReq{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req, binding.JSON).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
req.SetUpdateBy(user.GetUserId(c))
|
|
|
|
//数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
|
|
err = s.ResetPwd(&req, p)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
return
|
|
}
|
|
e.OK(req.GetId(), "更新成功")
|
|
}
|
|
|
|
// UpdatePwd
|
|
// @Summary 修改密码
|
|
// @Description 获取JSON
|
|
// @Tags 用户
|
|
// @Accept application/json
|
|
// @Product application/json
|
|
// @Param data body dto.PassWord true "body"
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/user/pwd/set [put]
|
|
// @Security Bearer
|
|
func (e SysUser) UpdatePwd(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.PassWord{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
Bind(&req).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
// 数据权限检查
|
|
p := actions.GetPermissionFromContext(c)
|
|
var hash []byte
|
|
if hash, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost); err != nil {
|
|
req.NewPassword = string(hash)
|
|
}
|
|
|
|
err = s.UpdatePwd(user.GetUserId(c), req.OldPassword, req.NewPassword, p)
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(http.StatusForbidden, err, "密码修改失败")
|
|
return
|
|
}
|
|
|
|
e.OK(nil, "密码修改成功")
|
|
}
|
|
|
|
// GetProfile
|
|
// @Summary 获取个人中心用户
|
|
// @Description 获取JSON
|
|
// @Tags 个人中心
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/user/profile [get]
|
|
// @Security Bearer
|
|
func (e SysUser) GetProfile(c *gin.Context) {
|
|
s := service.SysUser{}
|
|
req := dto.SysUserById{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
|
|
req.Id = user.GetUserId(c)
|
|
|
|
sysUser := models.SysUser{}
|
|
roles := make([]models.SysRole, 0)
|
|
posts := make([]models.SysPost, 0)
|
|
err = s.GetProfile(&req, &sysUser, &roles, &posts)
|
|
if err != nil {
|
|
e.Logger.Errorf("get user profile error, %s", err.Error())
|
|
e.Error(500, err, "获取用户信息失败")
|
|
return
|
|
}
|
|
e.OK(gin.H{
|
|
"user": sysUser,
|
|
"roles": roles,
|
|
"posts": posts,
|
|
}, "查询成功")
|
|
}
|
|
|
|
// GetInfo
|
|
// @Summary 获取个人信息
|
|
// @Description 获取JSON
|
|
// @Tags 个人中心
|
|
// @Success 200 {object} response.Response "{"code": 200, "data": [...]}"
|
|
// @Router /api/v1/getinfo [get]
|
|
// @Security Bearer
|
|
func (e SysUser) GetInfo(c *gin.Context) {
|
|
req := dto.SysUserById{}
|
|
s := service.SysUser{}
|
|
r := service.SysRole{}
|
|
err := e.MakeContext(c).
|
|
MakeOrm().
|
|
MakeService(&r.Service).
|
|
MakeService(&s.Service).
|
|
Errors
|
|
if err != nil {
|
|
e.Logger.Error(err)
|
|
e.Error(500, err, err.Error())
|
|
return
|
|
}
|
|
p := actions.GetPermissionFromContext(c)
|
|
var roles = make([]string, 1)
|
|
roles[0] = user.GetRoleName(c)
|
|
var permissions = make([]string, 1)
|
|
permissions[0] = "*:*:*"
|
|
var buttons = make([]string, 1)
|
|
buttons[0] = "*:*:*"
|
|
|
|
var mp = make(map[string]interface{})
|
|
mp["roles"] = roles
|
|
if user.GetRoleName(c) == "admin" || user.GetRoleName(c) == "系统管理员" {
|
|
mp["permissions"] = permissions
|
|
mp["buttons"] = buttons
|
|
} else {
|
|
list, _ := r.GetById(user.GetRoleId(c))
|
|
mp["permissions"] = list
|
|
mp["buttons"] = list
|
|
}
|
|
sysUser := models.SysUser{}
|
|
req.Id = user.GetUserId(c)
|
|
err = s.Get(&req, p, &sysUser)
|
|
if err != nil {
|
|
e.Error(http.StatusUnauthorized, err, "登录失败")
|
|
return
|
|
}
|
|
mp["introduction"] = " am a super administrator"
|
|
mp["avatar"] = "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"
|
|
if sysUser.Avatar != "" {
|
|
mp["avatar"] = sysUser.Avatar
|
|
}
|
|
mp["userName"] = sysUser.Username
|
|
mp["userId"] = sysUser.UserId
|
|
mp["deptId"] = sysUser.DeptId
|
|
mp["name"] = sysUser.NickName
|
|
mp["code"] = 200
|
|
e.OK(mp, "")
|
|
}
|