ASP .NET Core Razor 页面中的授权

Posted

技术标签:

【中文标题】ASP .NET Core Razor 页面中的授权【英文标题】:Authorization in ASP .NET Core Razor pages 【发布时间】:2019-12-20 00:03:59 【问题描述】:

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

我通读了this comprehensive document on authorization 并将其示例作为指导。

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

然后请求将被拒绝并返回 403 状态响应,因为“测试”政策规定每个人都是未经授权的。但是在实际操作中,动作是成功调用的。

【问题讨论】:

你能在 Startup 中显示你的 Configure 方法吗? 您还需要使用UseAuthentication() 中间件才能使这些授权策略真正发挥作用。 你添加UseAuthentication()中间件了吗 是的。我添加了身份验证中间件。 更新了github.com/dotnet/AspNetCore.Docs/pull/18949/files的文档 【参考方案1】:

Razor Pages 不支持 处理程序 级别的 [Authorize]。即您只能在PageModel 本身上授权一个页面作为一个整体,如docs 中所述:

策略不能在 Razor 页面处理程序级别应用,它们必须应用于页面。

如果授权整个页面不是一个可行的解决方案,您可能需要将您的 OnGetCreateAsync 处理程序移动到控制器/操作对中,这可以相应地归因于 [Authorize]

文档中还有一个相关的GitHub issue:

[Authorize] 过滤器属性自 Razor 页面 2.0 起已受支持,但请注意它适用于页面模型级别

如果您需要更好的解决方法,请参阅 akbar's answer 和 Jim Yabro's answer。

【讨论】:

【参考方案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);

【讨论】:

【参考方案3】:

我建议在 ASP.NET Core 中遵循 Razor Pages 授权约定,如下所示:

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://docs.microsoft.com/en-us/aspnet/core/security/authorization/razor-pages-authorization?view=aspnetcore-5.0

支持授权属性,但仅限于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();
    

来源:

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

【讨论】:

【参考方案4】:

不要使用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
    

【讨论】:

【参考方案5】:

我使用Permission-based Authorization in 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;
            
        
    
    
    

【讨论】:

以上是关于ASP .NET Core Razor 页面中的授权的主要内容,如果未能解决你的问题,请参考以下文章

Asp.Net Core Razor 页面中的远程验证

Asp.net Core Razor 页面中的引导警报

更改 ASP.NET Core Razor 页面中的默认登录页面?

将 ASP.NET Core Razor 页面中的默认页面更改为登录页面

如何使用 ASP.NET Core Razor 页面预选下拉列表中的项目

ASP.NET Core 2.2 Razor 页面中的自定义路由