我试图在这里围绕几个概念展开思考,但我不希望这个问题过于宽泛——基本上我们要做的是使用角色声明作为锁定我们 API 的权限,但我发现 access_token 是变得太大。
我们在服务器端使用 OpenIddict 和 ASP.NET Identity 3。我们已经实现了默认的 AspNetRoleClaims 表来存储我们对每个角色的声明 - 将它们用作权限。
我们使用基于自定义策略的声明授权来锁定我们的 API 端点,如下所示:
我发现的主要问题是包含我们声明的 access_token 变得非常大。我们正在尝试使数据库中的 ClaimType 和 Value 非常小,以使声明占用空间更小。我们有一个基本的 CRUD 类型权限方案,因此对于我们的 SPA 客户端应用程序中的每个“模块”或屏幕,有 4 个权限。我们添加到应用程序中的模块越多,access_token 中的声明就越多,并且我们的 Authorization Bearer 标头变得非常大。我担心随着应用程序的增长,这变得不是很有可扩展性。
因此,声明嵌入在 access_token 中,当我点击我的端点时,该端点被这样的自定义策略锁定......
[Authorize(Policy="MyModuleCanRead")]
[HttpGet]
public IEnumerable<MyViewModel> Get()
然后我可以在 AuthorizationHandler 中访问我的 ASP.NET 身份用户和 User.Claims。
如果这是一个明显的问题,请提前抱歉 - 但我想知道 - 为了让基于自定义策略的授权工作 - 是否绝对需要声明在 id_token 或 access_token 中才能调用处理程序?
如果我从 access_token 中删除声明,那么我的 AuthorizationHandler 代码不会被命中,并且我无法访问被我的自定义策略锁定的端点。
我想知道是否可以使用自定义声明策略,但在授权处理程序中具有检查声明的实际代码,以便声明不会随每个 HTTP 请求一起传递,而是从授权 cookie 获取服务器端或从数据库。
* 更新 *
Pintpoint 使用授权处理程序的答案以及关于如何从 cookie 中删除额外角色声明的评论实现了我想要的。
万一这对其他人有帮助 - 这是覆盖 UserClaimsPrincipalFactory 并防止将角色声明写入 cookie 的代码。(我有许多角色声明,因为权限和 cookie 和请求标头变得太大)
public class AppClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public AppClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
}
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var userId = await UserManager.GetUserIdAsync(user);
var userName = await UserManager.GetUserNameAsync(user);
var id = new ClaimsIdentity(Options.Cookies.ApplicationCookieAuthenticationScheme,
Options.ClaimsIdentity.UserNameClaimType,
Options.ClaimsIdentity.RoleClaimType);
id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId));
id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName));
if (UserManager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
await UserManager.GetSecurityStampAsync(user)));
}
// code removed that adds the role claims
if (UserManager.SupportsUserClaim)
{
id.AddClaims(await UserManager.GetClaimsAsync(user));
}
return new ClaimsPrincipal(id);
}
}