Identity 3 MVC 6 中的授权策略
Authorisation Policy in Identity 3 MVC 6
我已经做了很多研究,但仍然不确定我这样做是否正确。
我找到的最好的资源在这里
http://leastprivilege.com/2015/10/12/the-state-of-security-in-asp-net-5-and-mvc-6-authorization/
鉴于 ApplicationUser class 扩展为包括授权帐号列表,我想限制用户仅查看其授权帐户的报表(和其他基于的操作)。我认为这是一个非常常见的设计,但是网上的大多数文章都引用了以前版本的身份。
(PS 我在 Controller 构造函数中注入 UserManager)
这是我的动作
public IActionResult GetStatement(int accountNo,DateTime startDate,DateTime endDate)
{
var user = userManager.Users
.Include(u => u.AuthorisedAccounts)
.Where(u => u.Id == User.GetUserId())
.FirstOrDefault();
if (user.AuthorisedAccounts != null)
{
foreach (var account in user.AuthorisedAccounts)
{
if (account.AccountNo == accountNo)
return View(statementService.GetStatement(accountNo, startDate, endDate, 0));
}
}
return HttpUnauthorized();
}
我不禁觉得有更好的方法吗?
基本上我想根据动作参数授权。"accountNo"
关于采取何种方法的任何提示。
在这种情况下,您将使用基于资源的方式,帐户就是资源。此文档位于 https://docs.asp.net/en/latest/security/authorization/resourcebased.html
首先,您需要定义一个读取操作,
public static class Operations
{
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = "Read" };
}
现在您将拥有一个 AccountAccess 策略
public class AccountAuthorizationHandler : AuthorizationHandler<
OperationAuthorizationRequirement, Account>
{
IUserManager _userManager;
public AccountAuthorizationHandler(IUserManager userManager)
{
_userManager = userManager;
}
protected override void Handle(AuthorizationContext context,
OperationAuthorizationRequirement requirement,
Account resource)
{
// Pull the user ID claim out from the context.User
var userId = context.User.....
// Get the current user's account numbers.
var user = userManager.Users
.Include(u => u.AuthorisedAccounts)
.Where(u => u.Id == userId)
.FirstOrDefault();
}
// Now check if the user's account numbers match the resource accountNumber, and
// also check the operation type, in case you want to vary based on create, view etc.
if (user.AuthorisedAccounts.Contains(resource.AccountId &&
requirement.Name == "View")
{
context.Succeed(requirement);
}
}
之后在配置服务中的 DI 容器中注册您的策略;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization();
services.AddSingleton<IAuthorizationHandler,
AccountAuthorizationHandler>();
}
在您的控制器中注入 AuthorizationService;
public class AccountController : Controller
{
IAuthorizationService _authorizationService;
public AccountController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
}
然后,在您的控制器中,在加载帐户资源后,您可以执行类似
的操作
public async Task<IActionResult> View(int accountId)
{
Account account = accountManager.Find(accountId);
if (account == null)
{
return new HttpNotFoundResult();
}
if (await _authorizationService.AuthorizeAsync(User, account, Operations.Read))
{
return View(account);
}
else
{
return new ChallengeResult();
}
}
如果您想以一种允许您将其用于 [Authorize]
属性的方式定义您的授权策略,您可以改变所见的方法 in this article:
services.AddAuthorization(options =>
{
// inline policies
options.AddPolicy("AccessByAccountNumber", policy =>
{
policy.RequireDelegate((context, requirement) =>
{
var httpContext = (context as dynamic).HttpContext;
// Proceed to grab the account number from the request values
// and compare it against the user object stored in 'context.User'
});
});
});
这样做的缺点是您需要确保使用属性的所有操作都以一致的方式执行,即每次都对操作参数或路由参数使用相同的名称。
@blowdart 在控制器操作中使用 IAuthorizationService
的示例演示了一种使用和重新使用策略的方法,该策略允许将参数名称与策略本身分离。虽然我们可以看到 IAuthorizationService
没有提供强类型的泛型方法,但它似乎提供了一种不那么脆弱的方法来实现基于资源的策略。
我已经做了很多研究,但仍然不确定我这样做是否正确。 我找到的最好的资源在这里
http://leastprivilege.com/2015/10/12/the-state-of-security-in-asp-net-5-and-mvc-6-authorization/
鉴于 ApplicationUser class 扩展为包括授权帐号列表,我想限制用户仅查看其授权帐户的报表(和其他基于的操作)。我认为这是一个非常常见的设计,但是网上的大多数文章都引用了以前版本的身份。
(PS 我在 Controller 构造函数中注入 UserManager)
这是我的动作
public IActionResult GetStatement(int accountNo,DateTime startDate,DateTime endDate)
{
var user = userManager.Users
.Include(u => u.AuthorisedAccounts)
.Where(u => u.Id == User.GetUserId())
.FirstOrDefault();
if (user.AuthorisedAccounts != null)
{
foreach (var account in user.AuthorisedAccounts)
{
if (account.AccountNo == accountNo)
return View(statementService.GetStatement(accountNo, startDate, endDate, 0));
}
}
return HttpUnauthorized();
}
我不禁觉得有更好的方法吗? 基本上我想根据动作参数授权。"accountNo"
关于采取何种方法的任何提示。
在这种情况下,您将使用基于资源的方式,帐户就是资源。此文档位于 https://docs.asp.net/en/latest/security/authorization/resourcebased.html
首先,您需要定义一个读取操作,
public static class Operations
{
public static OperationAuthorizationRequirement Read =
new OperationAuthorizationRequirement { Name = "Read" };
}
现在您将拥有一个 AccountAccess 策略
public class AccountAuthorizationHandler : AuthorizationHandler<
OperationAuthorizationRequirement, Account>
{
IUserManager _userManager;
public AccountAuthorizationHandler(IUserManager userManager)
{
_userManager = userManager;
}
protected override void Handle(AuthorizationContext context,
OperationAuthorizationRequirement requirement,
Account resource)
{
// Pull the user ID claim out from the context.User
var userId = context.User.....
// Get the current user's account numbers.
var user = userManager.Users
.Include(u => u.AuthorisedAccounts)
.Where(u => u.Id == userId)
.FirstOrDefault();
}
// Now check if the user's account numbers match the resource accountNumber, and
// also check the operation type, in case you want to vary based on create, view etc.
if (user.AuthorisedAccounts.Contains(resource.AccountId &&
requirement.Name == "View")
{
context.Succeed(requirement);
}
}
之后在配置服务中的 DI 容器中注册您的策略;
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization();
services.AddSingleton<IAuthorizationHandler,
AccountAuthorizationHandler>();
}
在您的控制器中注入 AuthorizationService;
public class AccountController : Controller
{
IAuthorizationService _authorizationService;
public AccountController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
}
然后,在您的控制器中,在加载帐户资源后,您可以执行类似
的操作public async Task<IActionResult> View(int accountId)
{
Account account = accountManager.Find(accountId);
if (account == null)
{
return new HttpNotFoundResult();
}
if (await _authorizationService.AuthorizeAsync(User, account, Operations.Read))
{
return View(account);
}
else
{
return new ChallengeResult();
}
}
如果您想以一种允许您将其用于 [Authorize]
属性的方式定义您的授权策略,您可以改变所见的方法 in this article:
services.AddAuthorization(options =>
{
// inline policies
options.AddPolicy("AccessByAccountNumber", policy =>
{
policy.RequireDelegate((context, requirement) =>
{
var httpContext = (context as dynamic).HttpContext;
// Proceed to grab the account number from the request values
// and compare it against the user object stored in 'context.User'
});
});
});
这样做的缺点是您需要确保使用属性的所有操作都以一致的方式执行,即每次都对操作参数或路由参数使用相同的名称。
@blowdart 在控制器操作中使用 IAuthorizationService
的示例演示了一种使用和重新使用策略的方法,该策略允许将参数名称与策略本身分离。虽然我们可以看到 IAuthorizationService
没有提供强类型的泛型方法,但它似乎提供了一种不那么脆弱的方法来实现基于资源的策略。