ASP .NET Core Razor页面中的授权

时间:2019-08-13 12:19:15

标签: c# asp.net-core razor-pages

我无法在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状态响应被拒绝,因为“测试”策略指出每个人都是未经授权的。但是,在实际操作中,该操作已成功调用。

3 个答案:

答案 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中配置了策略,便可以从页面处理程序中检查这些策略。

  1. IAuthorizationService注入到页面模型构造函数中
  2. 从处理程序中调用AuthorizeAsync()
  3. 对结果的.Succeeded属性进行条件检查。
  4. 如果.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,而不是为了测试目的而查看整个视图,就像您没有担任该角色一样。