【发布时间】:2021-08-14 23:03:37
【问题描述】:
我正在使用 Razor Pages 和 Asp.Net Core Identity 创建一个简单的 Asp.Net Core Web 应用程序,但我遇到了一个问题,即应用到 PageModel 的策略的授权处理程序在应用到同一页面的策略后仍然执行尽管每个授权处理程序都与不同的需求类相关,但文件夹。我的问题是,即使在文件夹策略授权处理程序中调用 Context.Fail(),未经身份验证的用户似乎仍然可以访问页面,这会触发页面策略授权处理程序然后引发异常,因为 User 对象为空。我想实现一个简单的流程,其中对页面的请求首先通过它们所属的文件夹上设置的策略进行验证,好吗?继续 Page(并运行 Page 授权处理程序),不行,立即返回禁止响应。
非常感谢任何帮助。
要求:
public class SectionsAccessRequirement : IAuthorizationRequirement
{
public string SectionName { get; }
public SectionsAccessRequirement(string Name)
{
SectionName = Name;
}
}
public class RecordCreateRequirement : IAuthorizationRequirement { }
授权处理程序:
public class SectionsAccessHandler : AuthorizationHandler<SectionsAccessRequirement>
{
public IHttpContextAccessor _accessor;
public SectionsAccessHandler(IHttpContextAccessor Accessor) => _accessor = Accessor;
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SectionsAccessRequirement requirement)
{
// Require authentication
if (!_accessor.HttpContext.User.Identity.IsAuthenticated) context.Fail();
// Admin
if (context.User.HasClaim(c => c.Type == ClaimNameConstants.UserGroup && c.Value == UserGroupConstants.AdminGroup)) context.Succeed(requirement);
if (requirement.SectionName == SectionNameConstants.AdminSection) context.Fail();
// Client
if (requirement.SectionName == SectionNameConstants.ClientSection && context.User.HasClaim(c => c.Type == ClaimNameConstants.ClientSection)) context.Succeed(requirement);
return Task.CompletedTask;
}
}
public class RecordCreateAuthorizationHandler : AuthorizationHandler<RecordCreateRequirement>
{
private readonly UserManager<AppUser> _users;
public RecordCreateAuthorizationHandler(UserManager<AppUser> Users) => _users = Users;
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RecordCreateRequirement requirement)
{
// User ID
int sessionUserId = int.Parse(_users.GetUserId(context.User));
// Privileges
if (!context.User.HasClaim(c => c.Type == ClaimNameConstants.UserGroup && c.Value == UserGroupConstants.AdminGroup))
{
if (context.User.HasClaim(c => c.Type == ClaimNameConstants.ClientCreate)) context.Succeed(requirement);
}
else
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
我有这两种扩展方法:
public static class AuthorizationOptionsExtension
{
public static void AddPolicies(this AuthorizationOptions Options)
{
// Folders policies
Options.AddPolicy(PolicyNameConstants.AdminSectionPolicy, p => p.Requirements.Add(new SectionsAccessRequirement(SectionNameConstants.AdminSection)));
Options.AddPolicy(PolicyNameConstants.ClientSectionPolicy, p => p.Requirements.Add(new SectionsAccessRequirement(SectionNameConstants.ClientSection)));
// Pages policies
Options.AddPolicy(PolicyNameConstants.ClientRecordCreatePolicy, p => p.Requirements.Add(new Client.RecordCreateRequirement()));
// Fallback policy
Options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
}
}
还有:
public static class RazorPagesOptionsExtension
{
public static void AddFoldersAuthorization(this RazorPagesOptions Options)
{
Options.Conventions.AuthorizeFolder("/Admin", PolicyNameConstants.AdminSectionPolicy);
Options.Conventions.AuthorizeFolder("/Client", PolicyNameConstants.ClientSectionPolicy);
}
}
使用 Authorize 属性应用页面的策略:
[Authorize(Policy = PolicyNameConstants.ClientRecordCreatePolicy)]
public class CreateModel : PageModel
{ ... }
这是我的启动课,我正在使用 Asp.Net Core Identity:
public class Startup
{
private readonly IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
// Add (and configure) services to the container
public void ConfigureServices(IServiceCollection services)
{
// Global application settings (formerly known as Web.config) and other settings
services.Configure<ApplicationSettings>(_config);
// Application
services.AddApplicationLayerServices();
services.AddRazorPages();
services.AddHttpContextAccessor();
services.Configure<RazorViewEngineOptions>(options =>
{
options.PageViewLocationFormats.Add("/Pages/Shared/Partials/{0}" + RazorViewEngine.ViewExtension);
options.PageViewLocationFormats.Add("/Pages/Client/Partials/{0}" + RazorViewEngine.ViewExtension);
});
// Data store
services.AddDbContext<DataContext>(options => options.UseOracle(_config.GetConnectionString("AppConnectionString")));
// Security
services.AddIdentity<AppUser, IdentityRole<int>>(options => {
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 8;
}).AddEntityFrameworkStores<DataContext>();
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(15);
options.LoginPath = "/SignIn";
options.AccessDeniedPath = "/FourZeroSomething";
options.SlidingExpiration = true;
});
services.AddAccessControlLayerServices();
services.AddAuthorization(options => options.AddPolicies());
services.Configure<RazorPagesOptions>(options => options.AddFoldersAuthorization());
}
// Configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
// Navigation
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// Security
app.UseAuthentication();
app.UseAuthorization();
// Endpoints
app.UseEndpoints(endpoints => endpoints.MapRazorPages());
}
}
}
【问题讨论】:
标签: c# asp.net-core authorization razor-pages asp.net-core-identity