【问题标题】:Authorization in ASP .NET Core Razor pagesASP .NET Core Razor 页面中的授权
【发布时间】: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()中间件了吗
  • 是的。我添加了身份验证中间件。

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


【解决方案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 中配置了您的政策,您就可以在页面处理程序中检查这些政策。

        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
            }
        }
        

        【讨论】:

          【解决方案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;
                      }
                  }
              }
              
              
          

          【讨论】:

            猜你喜欢
            • 2020-12-21
            • 2019-11-22
            • 1970-01-01
            • 2022-08-17
            • 2020-03-12
            • 2019-09-21
            • 2018-07-30
            • 2020-11-16
            • 1970-01-01
            相关资源
            最近更新 更多