Razor 页面发现和授权

Razor Pages Discovery and Authorization

我正在使用 ASP.NET Core 3.0 和 Razor Pages 开发网络应用程序。我想添加一个功能,允许用户按页面名称搜索 - 假设用户搜索 'password',结果是 'Change Password',这是一个 Razor 页面。

我想页面模型应该是这样的:

[SearchablePage(Name="Manage Account", Keywords="password,username,change")]
public class ManageAccountModel : PageModel
{
   ...
}

到目前为止,我设法通过注入 IActionDescriptorCollectionProvider 并查找 PageActionDescriptor 项来发现页面。这会显示应用程序中的所有页面。

我不确定如何获取每个页面的实际 PageModel class,以便确定自定义搜索属性的值。

我也在尝试弄清楚用户是否有权查看该页面 - 是来自授权属性还是来自 [=43= 中配置的授权约定].

我们将不胜感激任何帮助或指导!

谢谢!

更新

我设法找到了框架提供的 IAuthorizationService - documentation。现在的诀窍是检索剃刀页面的所有策略。

我有以下页面列出了我的网络应用程序中的所有路由。我用来诊断端点的。用作起点可能很有用。我不确定您将如何获得授权信息。

public class RoutesModel : PageModel {
    private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;

    public RoutesModel(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider) {
        this._actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
    }

    public List<RouteInfo> Routes { get; set; }

    public void OnGet() {
        Routes = _actionDescriptorCollectionProvider.ActionDescriptors.Items
                .Select(x => new RouteInfo {
                    Action = x.RouteValues["Action"],
                    Controller = x.RouteValues["Controller"],
                    Name = x.AttributeRouteInfo?.Name,
                    Template = x.AttributeRouteInfo?.Template,
                    Constraint = x.ActionConstraints == null ? "" : JsonConvert.SerializeObject(x.ActionConstraints)
                })
            .OrderBy(r => r.Template)
            .ToList();
    }

    public class RouteInfo {
        public string Template { get; set; }
        public string Name { get; set; }
        public string Controller { get; set; }
        public string Action { get; set; }
        public string Constraint { get; set; }
    }
}

我设法找到了一个可行的解决方案,目前我已经使用页面而不是控制器和视图对其进行了测试。

所需接口

  • IActionDescriptorCollectionProvider - 提供所有 Razor 页面的列表。
  • PageLoader - 加载 Razor 页面,解析其安全策略和 class 属性。
  • IAuthorizationService- 确定用户是否有权使用策略。

步骤

获取所有剃须刀页面的列表。

var pageDescriptors = _descriptorProvider.ActionDescriptors.Items
  .OfType<PageActionDescriptor>()
  .ToArray();

遍历页面并加载每个页面:

var compiledPage = await _pageLoader.LoadAsync(pageDescriptor);

此时您可以根据添加到页面模型的属性进行一些处理。请注意,您添加到页面模型 class 的任何属性将在 EndpointMetadata 中自动解析,无需进行自定义反射工作!

var pageMetadata = compiledPage.EndpointMetadata
  .OfType<PageMetadataAttribute>() // My custom attribute.
  .FirstOrDefault();

请注意,策略和授权将以 AuthorizeAttribute 实例的形式添加到 Razor 页面元数据中。

提取授权属性,遍历它们并求值。

var authorization = compiledPage.EndpointMetadata
  .OfType<AuthorizeAttribute>()
  .ToArray();

foreach (var auth in authorization)
{
  if (!string.IsNullOrEmpty(auth.Policy))
  {
    var authResult = await _authorizationService.AuthorizeAsync(
      _httpContextAccessor.HttpContext.User,
      auth.Policy);

    if (!authResult.Succeeded) return; // Do stuff here.
}