最佳实践:自定义 asp.net 核心身份授权
best practice: customize asp.net core identity authorization
我是 asp.net 身份服务器的新手。我知道如何自定义 IdentityUser 实体和脚手架/覆盖 Identity UI。在这些情况下,我正在寻找有关授权的高级操作方法和最佳实践:
应用程序中的组件需要考虑这些项目以进行授权:
- 角色
- 位置
- 除法
- 实体(应用程序中的特定组件。喜欢"Manage News")
来自 class 网络表单背景,我倾向于这样定义角色:
public int assignId; //key
public int userId;
public int roleId;
public int? locationId;
public int? divisionId;
public int? entityId;
真实场景
- 具有角色 "Global Admin" 的用户 "Adam" 拥有所有权限。
- 具有角色 "Admin" 和位置 "Indy" 的用户 "Joe" 有权访问 "Indy" 位置中的每个实体。
- 具有角色 "Admin" 和位置 "Indy" 和部门 "IT" 的用户 "Blow" 有权访问 "Indy"[=] 中的每个 "IT" 实体39=]
- 具有角色 "Admin" 和位置 "Chicago" 以及部门 "Safety" 和实体 "News" 的用户 "Joe" 可以 post 安全部门的新闻仅限芝加哥。 (除了上面关于 Joe 和 Indy 的规则)
所以,我的问题是?
使用 asp.net 核心 2.1 身份处理此类授权规则/策略的最佳方式是什么?添加像 "loc"/"indy" 这样的声明?
我会设置自定义授权处理程序来检查声明吗?或者我会设置一个中间件 table 来处理关联,就像我在传统的网络表单时代一样?或者有针对这种情况的最佳实践吗??
感谢您的帮助!!!!!!!
早期版本的 ASP.NET 使用了 基于角色的 方法。但是,在这种情况下,首选新的 Claims-Based 方法。因为我们很难确定允许哪个角色访问资源。
假设您在上面描述的三个用户和声明:
Adam
:角色=全局管理员
Joe
:角色=管理员;位置=印地&位置=芝加哥;划分=安全;实体=新闻
Blow
:管理员;位置=印地;除法 = IT ;
AspNetUserClaims
table 记录用户的声明如下:
编号 |用户名 |索赔类型 |索赔价值 |
----|:------|:--------|:----------:|
3 | 3ff3d2db-5a8f-4b01-99b5-fe46d22c240c |角色 |全局管理员
4 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |角色 |管理员
5 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |地点 |印地
6 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |地点 |芝加哥
8 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |事业部|安全
9 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |实体 |新闻
10 | b60c7b75-e31b-4856-ba98-666d013c8201 |角色 |管理员
11 | b60c7b75-e31b-4856-ba98-666d013c8201 |地点 |印地
15 | b60c7b75-e31b-4856-ba98-666d013c8201 |事业部|它
如您所见,Claim-Based方法的记录相当简单明了。当需要授权用户时,我们可以将用户的声明与策略进行比较:
services.AddAuthorization(opts=> {
// ... other policy ...
// ...
opts.AddPolicy("Check:Role|Location|Division|Entity", pb=>
pb.RequireAssertion(async context=> await RldeChecker.Handle(context) )
);
})
Checker.Handle(context) 这是一个简单的静态方法,它接收 AuthorizationHandlerContex 的实例作为参数并检查如果用户可以访问某些特定资源。
为了更清楚,我们可以添加一个 PolicyChecker/ 文件夹,然后将 RldeChecker
class 放入其中:
public class RldeChecker
{
// ...
public static async Task<bool> Handle(AuthorizationHandlerContext context) {
var user = context.User;
// bypass all checks
if (user.HasClaim("Role","Global Admin" )) { return true; }
try
{
// retrieve the user claims
var userLocation = user.FindFirst("Location")?.Value;
var userDivision = user.FindFirst("Division")?.Value;
var userEntity = user.FindFirst("Entity")?.Value;
// retrieve the resource that the user want to access at runtime
var resource = (Dictionary<string, string>)context.Resource;
var targetLocation = resource["Location"];
var targetDivision = resource["Division"];
var targetEntity = resource["Entity"];
// check for local admin
// ...
}
catch {
return false;
}
return false;
}
}
当我们想要在操作方法中授权用户时,我们可以简单地注入一个 IAuthorizationService
的实例以通过 authService.Authorize(user,resource,"Check:Role|Location|Division|Entity")
进行检查。此外,基于声明的方法允许我们以服务的方式使用它,然后我们可以根据需要在任何地方注入它,例如,根据当前用户的 Location/Division/Entity 显示不同的内容:
var resource = new Dictionary<string, string>() {
{ "Location","Indy"},
{ "Division","IT"},
{ "Entity","News"},
};
var x = await this._authorizationService.AuthorizeAsync(User, resource, "Check:Role|Location|Division|Entity");
if (x.Succeeded)
{
return View();
}
else
{
return new ForbidResult();
}
我是 asp.net 身份服务器的新手。我知道如何自定义 IdentityUser 实体和脚手架/覆盖 Identity UI。在这些情况下,我正在寻找有关授权的高级操作方法和最佳实践:
应用程序中的组件需要考虑这些项目以进行授权:
- 角色
- 位置
- 除法
- 实体(应用程序中的特定组件。喜欢"Manage News")
来自 class 网络表单背景,我倾向于这样定义角色:
public int assignId; //key
public int userId;
public int roleId;
public int? locationId;
public int? divisionId;
public int? entityId;
真实场景
- 具有角色 "Global Admin" 的用户 "Adam" 拥有所有权限。
- 具有角色 "Admin" 和位置 "Indy" 的用户 "Joe" 有权访问 "Indy" 位置中的每个实体。
- 具有角色 "Admin" 和位置 "Indy" 和部门 "IT" 的用户 "Blow" 有权访问 "Indy"[=] 中的每个 "IT" 实体39=]
- 具有角色 "Admin" 和位置 "Chicago" 以及部门 "Safety" 和实体 "News" 的用户 "Joe" 可以 post 安全部门的新闻仅限芝加哥。 (除了上面关于 Joe 和 Indy 的规则)
所以,我的问题是?
使用 asp.net 核心 2.1 身份处理此类授权规则/策略的最佳方式是什么?添加像 "loc"/"indy" 这样的声明?
我会设置自定义授权处理程序来检查声明吗?或者我会设置一个中间件 table 来处理关联,就像我在传统的网络表单时代一样?或者有针对这种情况的最佳实践吗??
感谢您的帮助!!!!!!!
早期版本的 ASP.NET 使用了 基于角色的 方法。但是,在这种情况下,首选新的 Claims-Based 方法。因为我们很难确定允许哪个角色访问资源。
假设您在上面描述的三个用户和声明:
Adam
:角色=全局管理员Joe
:角色=管理员;位置=印地&位置=芝加哥;划分=安全;实体=新闻Blow
:管理员;位置=印地;除法 = IT ;
AspNetUserClaims
table 记录用户的声明如下:
编号 |用户名 |索赔类型 |索赔价值 |
----|:------|:--------|:----------:|
3 | 3ff3d2db-5a8f-4b01-99b5-fe46d22c240c |角色 |全局管理员
4 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |角色 |管理员
5 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |地点 |印地
6 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |地点 |芝加哥
8 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |事业部|安全
9 | cea5d395-fd46-4e6a-aa81-2f4c011b74be |实体 |新闻
10 | b60c7b75-e31b-4856-ba98-666d013c8201 |角色 |管理员
11 | b60c7b75-e31b-4856-ba98-666d013c8201 |地点 |印地
15 | b60c7b75-e31b-4856-ba98-666d013c8201 |事业部|它
如您所见,Claim-Based方法的记录相当简单明了。当需要授权用户时,我们可以将用户的声明与策略进行比较:
services.AddAuthorization(opts=> {
// ... other policy ...
// ...
opts.AddPolicy("Check:Role|Location|Division|Entity", pb=>
pb.RequireAssertion(async context=> await RldeChecker.Handle(context) )
);
})
Checker.Handle(context) 这是一个简单的静态方法,它接收 AuthorizationHandlerContex 的实例作为参数并检查如果用户可以访问某些特定资源。
为了更清楚,我们可以添加一个 PolicyChecker/ 文件夹,然后将 RldeChecker
class 放入其中:
public class RldeChecker
{
// ...
public static async Task<bool> Handle(AuthorizationHandlerContext context) {
var user = context.User;
// bypass all checks
if (user.HasClaim("Role","Global Admin" )) { return true; }
try
{
// retrieve the user claims
var userLocation = user.FindFirst("Location")?.Value;
var userDivision = user.FindFirst("Division")?.Value;
var userEntity = user.FindFirst("Entity")?.Value;
// retrieve the resource that the user want to access at runtime
var resource = (Dictionary<string, string>)context.Resource;
var targetLocation = resource["Location"];
var targetDivision = resource["Division"];
var targetEntity = resource["Entity"];
// check for local admin
// ...
}
catch {
return false;
}
return false;
}
}
当我们想要在操作方法中授权用户时,我们可以简单地注入一个 IAuthorizationService
的实例以通过 authService.Authorize(user,resource,"Check:Role|Location|Division|Entity")
进行检查。此外,基于声明的方法允许我们以服务的方式使用它,然后我们可以根据需要在任何地方注入它,例如,根据当前用户的 Location/Division/Entity 显示不同的内容:
var resource = new Dictionary<string, string>() {
{ "Location","Indy"},
{ "Division","IT"},
{ "Entity","News"},
};
var x = await this._authorizationService.AuthorizeAsync(User, resource, "Check:Role|Location|Division|Entity");
if (x.Succeeded)
{
return View();
}
else
{
return new ForbidResult();
}