diff --git a/app/admin/apis/sys_user.go b/app/admin/apis/sys_user.go index 07b8c6dd..5d595dea 100644 --- a/app/admin/apis/sys_user.go +++ b/app/admin/apis/sys_user.go @@ -444,7 +444,6 @@ func (e SysUser) GetInfo(c *gin.Context) { 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) @@ -464,7 +463,14 @@ func (e SysUser) GetInfo(c *gin.Context) { } sysUser := models.SysUser{} req.Id = user.GetUserId(c) - err = s.Get(&req, p, &sysUser) + // Unscoped on purpose: the id is the caller's own, taken from the token. + // This used to go through Get with whatever GetPermissionFromContext + // returned - and this route installs no PermissionAction, so that was the + // zero value. An unset scope is not a recognised one, so once unknown + // scopes started failing closed rather than silently matching everything, + // every login on a deployment with enabledp: true ended here with a 401 + // and the browser went straight back to the login page. + err = s.GetSelf(&req, &sysUser) if err != nil { e.Error(http.StatusUnauthorized, err, "登录失败") return diff --git a/app/admin/router/sys_api.go b/app/admin/router/sys_api.go index 1eba4c38..39586cf2 100644 --- a/app/admin/router/sys_api.go +++ b/app/admin/router/sys_api.go @@ -5,6 +5,7 @@ import ( jwt "github.com/go-admin-team/go-admin-core/v2/jwtauth" "go-admin/app/admin/apis" + "go-admin/common/actions" "go-admin/common/middleware" ) @@ -15,7 +16,10 @@ func init() { // registerSysApiRouter func registerSysApiRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { api := apis.SysApi{} - r := v1.Group("/sys-api").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + // PermissionAction is not optional here: all three handlers below read the + // data permission out of the context, and without it they read the zero + // value - an unset scope, which Permission now fails closed on. + r := v1.Group("/sys-api").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()).Use(actions.PermissionAction()) { r.GET("", api.GetPage) r.GET("/:id", api.Get) diff --git a/app/admin/service/sys_user.go b/app/admin/service/sys_user.go index 839a9b3b..320be907 100644 --- a/app/admin/service/sys_user.go +++ b/app/admin/service/sys_user.go @@ -38,6 +38,30 @@ func (e *SysUser) GetPage(c *dto.SysUserGetPageReq, p *actions.DataPermission, l return nil } +// GetSelf 获取调用者自己的 SysUser 对象,不套数据权限 +// +// The data scope answers "whose rows may this user see"; the caller here is +// reading their own, and the id comes from the token, so there is nothing left +// for a scope to restrict. Applying one is not a stricter version of this +// query - it is a broken one. DataScopeSelf matches on create_by, and a user +// account is created by whoever added it, so a scoped self-read would fail for +// every user who did not create their own account. +// +// GetProfile has always read the same row this way, with no scope at all. +func (e *SysUser) GetSelf(d *dto.SysUserById, model *models.SysUser) error { + err := e.Orm.First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("db error: %s", err) + return err + } + if err != nil { + e.Log.Errorf("db error: %s", err) + return err + } + return nil +} + // Get 获取SysUser对象 func (e *SysUser) Get(d *dto.SysUserById, p *actions.DataPermission, model *models.SysUser) error { var data models.SysUser