我无法在ASP.NET Core中实现基于策略的授权,以在剃须刀页面上执行操作。
我通读了this comprehensive document on authorization,并以其示例为指导。
剃刀页面操作代码:
[Authorize(Policy = "test")]
public async Task<IActionResult> OnGetCreateAsync(string id)
服务配置中的代码:
_ = services.AddAuthorization(options => {
options.AddPolicy("test", policy =>
policy.RequireAssertion(context =>
false));
});
我希望如果我调用动作或端点服务,例如
GET /Account?handler=Create
然后,该请求将以403状态响应被拒绝,因为“测试”策略指出每个人都是未经授权的。但是,在实际操作中,该操作已成功调用。
答案 0 :(得分:5)
Razor Pages当前在 handler 级别不支持[Authorize]
。即,您只能在PageModel
本身上授权整个页面 。 This是我在文档中可以找到的最接近的东西:
Authorize属性可以应用于
PageModel
如果对页面进行整体授权不是可行的解决方案,则可能需要将OnGetCreateAsync
处理程序移至控制器/操作对中,并可以相应地将其归因于[Authorize]
。
文档中还有一个与此相关的GitHub issue:
自2.0版以来,Razor Pages中一直支持
下有效[Authorize]
过滤器属性,但是请注意,该属性在页面模型 class 级别
答案 1 :(得分:2)
另一种解决方案是通过if子句检查身份验证。
if (!HttpContext.User.Identity.IsAuthenticated)
{
return Redirect("/Front/Index");
}
,您也可以通过查找角色来检查roles
:
var user = await _userManager.FindByEmailAsync(model.Email);
var roles = await _userManager.GetRolesAsync(user);
答案 2 :(得分:0)
由于问题并没有说明AuthorizeAttribute
绝对是实现要求,所以我将提出一种替代文档的方法。
一旦在Startup.cs
中配置了策略,便可以从页面处理程序中检查这些策略。
IAuthorizationService
注入到页面模型构造函数中AuthorizeAsync()
。.Succeeded
属性进行条件检查。.Succeeded
为假,则返回Forbid()
结果。这与[Authorize(Policy=...)]
的结果几乎相同,但是在页面生命周期的稍后执行。请注意这一点,以防万一您的授权策略试图做复杂的事情。对于我现在可以想到的大多数用例,此解决方案都是令人满意的。
using Microsoft.AspNetCore.Authorization;
// ...
public class TestPageModel : PageModel {
readonly IAuthorizationService AuthorizationService;
public TestPageModel(IAuthorizationService authorizationService) {
AuthorizationService= authorizationService;
}
// Everyone can see this handler.
public void OnGet() { }
// Everyone can access this handler, but will be rejected after the check.
public async Task<IActionResult> OnPostAsync() {
// This is your policy you've defined in Startup.cs
var policyCheck = await AuthorizationService.AuthorizeAsync(User, "test");
// Check the result, and return a forbid result to the user if failed.
if (!policyCheck.Succeeded) {
return Forbid();
}
// ...
return Page(); // Or RedirectToPage etc
}
}
除了问题的范围外,还有一些其他注意事项。
首先,请注意,您可以从视图中访问该服务。您需要确保在页面本身或_ViewImports.cshtml
中存在using语句。
@page
@model App.Pages.TestPageModel
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
@{
var test = await AuthorizationService.AuthorizeAsync(User, "test");
}
@if (test.Succeeded) {
<span>You passed the test!</span>
}
如果您不喜欢这种外观,可以将等待的呼叫嵌入条件检查中并直接将.Succeeded
链接到该条件检查中,或者可以将测试声明为扩展方法,以便检查更具可读性。
public static class PassesTestExtension {
public static async Task<bool> PassesTest(this IAuthorizationService authorizationService, ClaimsPrincipal user) {
var check = await authorizationService.AuthorizeAsync(user, "test");
return check.Succeeded;
}
}
您的条件检查现在看起来像这样:
@if (await AuthorizationService.PassesTest(User)) {
<span>You passed the test!</span>
}
除了易读性之外,扩展方法的另一个好处是,您可以快速对其进行修改以返回!check.Succeeded
,而不是为了测试目的而查看整个视图,就像您没有担任该角色一样。