ASP .NET Core Razor页面中的授权

19

我无法在ASP .NET Core中为Razor页面上的操作实现基于策略的授权。

我阅读了此授权的详尽文档,并将其示例用作指南。

Razor页面操作代码:

[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

如果“test”策略规定每个人都未经授权,则请求将以403状态响应被拒绝。然而,在实际操作中,该操作成功调用。


你能展示一下在Startup中的Configure方法吗? - Nemanja Todorovic
你还需要使用 UseAuthentication() 中间件,才能使这些授权策略真正起作用。 - Vidmantas Blazevicius
你是否已经添加了 UseAuthentication() 中间件? - Praneet Nadkar
是的,我已经添加了身份验证中间件。 - shertu
更新文档请查看 https://github.com/dotnet/AspNetCore.Docs/pull/18949/files - RickAndMSFT
5个回答

16
Razor Pages不支持在handler级别使用[Authorize],即你只能在PageModel本身上授权整个页面,详见文档

不能在Razor Page handler级别应用策略,必须应用到页面上。

如果将整个页面授权不可行的话,你可能需要将OnGetCreateAsync handler移到一个控制器/操作对中,并相应地加上[Authorize]
此外,文档中还有一个相关的GitHub问题

[Authorize]过滤器属性自2.0版本以来已在Razor Pages中得到支持,但请注意它仅适用于页面模型类级别。

如果您需要更好的解决方法,请参见akbar的答案Jim Yabro的答案

5
我建议在ASP.NET Core中遵循Razor页面授权约定,如下所示:
services.AddRazorPages(options =>
{
    options.Conventions.AuthorizePage("/Contact");
    options.Conventions.AuthorizeFolder("/Private");
    options.Conventions.AllowAnonymousToPage("/Private/PublicPage");
    options.Conventions.AllowAnonymousToFolder("/Private/PublicPages");
});

在您使用策略 test 的情况下,它应该像这样:

options.Conventions.AuthorizePage("/Account", "test");

来源:

https://learn.microsoft.com/en-us/aspnet/core/security/authorization/razor-pages-authorization?view=aspnetcore-5.0

Authorize 属性受支持,但仅可用于 PageModel,例如:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace PageFilter.Pages
{
    [Authorize]
    public class ModelWithAuthFilterModel : PageModel
    {
        public IActionResult OnGet() => Page();
    }
}

Source:

https://learn.microsoft.com/en-us/aspnet/core/razor-pages/filter?view=aspnetcore-5.0#authorize-filter-attribute


我能否像MVC中那样设置一个模式路由?还是不可能的? - aj go
@ajgo 不确定,但文档可能会根据每页或每个文件夹来设置。 - Ogglas

5
另一种解决方法是通过if子句检查认证。像这样:

if (!HttpContext.User.Identity.IsAuthenticated)
    {
      return Redirect("/Front/Index");
    }

你可以通过查找角色(role)来检查其中的roles
var user = await _userManager.FindByEmailAsync(model.Email);
var roles = await _userManager.GetRolesAsync(user);

2
不要使用AuthorizeAttribute,因为它不受支持。
相反,一旦在Startup.cs中配置了策略,您将能够从页面处理程序中检查这些策略。
  1. IAuthorizationService注入到您的页面模型构造函数中
  2. 在处理程序内部调用AuthorizeAsync()
  3. 对结果的.Succeeded属性运行条件检查。
  4. 如果.Succeeded为false,则返回一个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
    }
}

0

我的解决方案使用 ASP.NET Core中基于权限的授权

    [Authorize(Permissions.PageX.AddParameter)]
    public async Task<IActionResult> OnPostAddParameterAsync(uint id, string key, string value)
    {
        if (!this.ArePermissionsValid()) return Forbid();
        /// ...
    }

    public static class PageExtensions
    {
    
        public static bool ArePermissionsValid(this PageModel page)
        {
            try
            {
                var authorizeAttribute = new StackTrace().GetFrames().FirstOrDefault(x =>  x.GetMethod().Name.StartsWith("On")).GetMethod().GetCustomAttribute<AuthorizeAttribute>();
                if (authorizeAttribute == null) return true;
                var hasPermissions = page.User.Claims.Any(x => x.Type.Equals("permission") && x.Value.Equals(authorizeAttribute.Policy));
                return hasPermissions;
            }
            catch (Exception e)
            {
                Log.Error($"${nameof(PageExtensions)}.{nameof(ArePermissionsValid)} | {e.Message}");
                return false;
            }
        }
    }
    
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接