using System.Security.Claims; using Microsoft.EntityFrameworkCore; using Rmsys.Infrastructure; namespace Rmsys.Api.Auth; /// /// 数据权限范围(sysusers.DataScope)。 /// /// 取值约定: /// 「全部处室」 → 不限 /// 「本处室」 → 只能看本处室(sysusers.DeptId)的干部与材料 /// 「全部处室(只读)」→ 能看全部,但不能做任何写操作 /// /// 为什么要单独抽出来:此前 DataScope 只在登录响应里回显,查询端一行没用, /// 导致「本处室」账号能拉到全部处室的干部,属于横向越权。 /// public static class ScopeGuard { public const string AllOfAll = "全部处室"; public const string OwnDept = "本处室"; public const string AllReadOnly = "全部处室(只读)"; public sealed record Scope(bool IsAll, int? DeptId, bool ReadOnly, string Raw) { /// 是否允许写操作 public bool CanWrite => !ReadOnly; } /// 按当前登录人解析数据范围;查不到账号时按「最严格」处理(只读、无部门) public static async Task ResolveAsync(ClaimsPrincipal p, RmsysDbContext db) { var acc = p.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(acc)) return new Scope(false, null, true, "unknown"); var u = await db.SysUsers.AsNoTracking() .Where(x => x.Account == acc) .Select(x => new { x.DataScope, x.DeptId }) .FirstOrDefaultAsync(); if (u == null) return new Scope(false, null, true, "unknown"); var raw = string.IsNullOrWhiteSpace(u.DataScope) ? AllOfAll : u.DataScope!; var isAll = raw.StartsWith("全部处室", StringComparison.Ordinal); var readOnly = raw.Contains("只读", StringComparison.Ordinal); return new Scope(isAll, u.DeptId, readOnly, raw); } /// 只读账号写操作的统一拒绝响应 public static IResult ReadOnlyDenied() => Results.Json(new { ok = false, message = "当前账号为「只读」权限,不能执行修改操作" }, statusCode: 403); }