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);
}