c# - Asp .Net Core 为什么即使用户未通过身份验证也会调用我的授权处理程序?

标签 c# asp.net-core

我有一个问题,如果我手动转到登录后的页面,我会在我的一个保单句柄中遇到异常,因为它找不到 claim 。

为什么会发生这种情况而不是将用户重定向到登录页面,因为他没有通过身份验证?我什至设置了身份验证方案,因为我所有的页面都有

[Authorize("scheme"), Policy = "policy"]

这是我的整个启动代码

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication()
         .AddCookie("ProductionAuth", options =>
         {
             options.ExpireTimeSpan = TimeSpan.FromDays(1);
             options.LoginPath = new PathString("/Production/Index");
             options.LogoutPath = new PathString("/Production/Logout");
             options.AccessDeniedPath = new PathString("/Production/AccessDenied/");
             options.SlidingExpiration = true;
         })
        .AddCookie("AdministrationAuth", options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromDays(1);
            options.LoginPath = new PathString("/Administration/Index");
            options.LogoutPath = new PathString("/Administration/Logout");
            options.AccessDeniedPath = new PathString("/Administration/AccessDenied/");
            options.SlidingExpiration = true;
        });

        services.AddAuthorization(options =>
        {
            options.AddPolicy("HasArranqueActivo", policy =>
                policy.RequireAuthenticatedUser()
                .AddAuthenticationSchemes("ProductionAuth")
                .Requirements.Add(new HasArranqueActivoRequirement()
            ));

            options.AddPolicy("HasArranqueInactivo", policy =>
                 policy.RequireAuthenticatedUser()
                 .AddAuthenticationSchemes("ProductionAuth")
                .Requirements.Add(new HasArranqueInactivoRequirement()
            ));
                 options.AddPolicy("IsParagemNotOnGoing", policy =>
                 policy.RequireAuthenticatedUser()
                 .AddAuthenticationSchemes("ProductionAuth")
                 .Requirements.Add(new IsParagemNotOnGoingRequirement()
            ));
                 options.AddPolicy("IsParagemOnGoing", policy =>
                 policy.RequireAuthenticatedUser()
                 .AddAuthenticationSchemes("ProductionAuth")
                 .Requirements.Add(new IsParagemOnGoingRequirement()
            ));
        });

        services.AddMemoryCache();

        services.AddMvc()
         .AddRazorPagesOptions(options =>
         {
             options.AllowAreas = true;
             options.Conventions.AuthorizeAreaFolder("Administration", "/Account");
             options.Conventions.AuthorizeAreaFolder("Production", "/Account");
         })
         .AddNToastNotifyToastr(new ToastrOptions()
         {
             ProgressBar = true,
             TimeOut = 3000,
             PositionClass = ToastPositions.TopFullWidth,
             PreventDuplicates = true,
             TapToDismiss = true
         })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseNToastNotify();
        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

这是我的处理程序,每个处理程序基本相同。要求很空洞, body 里什么都没有。

public class IsParagemNotOnGoingHandler : AuthorizationHandler<IsParagemNotOnGoingRequirement>
{
    private readonly DatabaseContext _context;

    public IsParagemNotOnGoingHandler(DatabaseContext context)
    {
        _context = context;
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsParagemNotOnGoingRequirement requirement)
    {
        // Get the context       
        var redirectContext = context.Resource as AuthorizationFilterContext;

        var registoId = Convert.ToInt32(context.User.FindFirst(c => c.Type == ClaimTypes.PrimarySid).Value);
        bool IsRegistoOnGoing = _context.ParagensRegistos.Any(pr => pr.RegistoId == registoId && pr.HoraFim == null);

        if (!IsRegistoOnGoing)
        {
            context.Succeed(requirement);
        }
        else
        {
            redirectContext.Result = new RedirectToPageResult("/Paragem");
            context.Succeed(requirement);
        }
            
        return Task.CompletedTask;
    }
}

这是个异常(exception)

An unhandled exception occurred while processing the request. NullReferenceException: Object reference not set to an instance of an object. NoPaper.Policies.IsParagemNotOnGoingHandler.HandleRequirementAsync(AuthorizationHandlerContext context, IsParagemNotOnGoingRequirement requirement) in IsParagemNotOnGoingHandler.cs, line 27

Stack Query Cookies Headers NullReferenceException: Object reference not set to an instance of an object. NoPaper.Policies.IsParagemNotOnGoingHandler.HandleRequirementAsync(AuthorizationHandlerContext context, IsParagemNotOnGoingRequirement requirement) in IsParagemNotOnGoingHandler.cs + var registoId = Convert.ToInt32(context.User.FindFirst(c => c.Type == ClaimTypes.PrimarySid).Value); Microsoft.AspNetCore.Authorization.AuthorizationHandler.HandleAsync(AuthorizationHandlerContext context) Microsoft.AspNetCore.Authorization.DefaultAuthorizationService.AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements) Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource) Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter.OnAuthorizationAsync(AuthorizationFilterContext context) Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync() Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync() Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext) Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) NToastNotify.NtoastNotifyAjaxToastsMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) Microsoft.AspNetCore.Builder.UseMiddlewareExtensions+<>c__DisplayClass5_1+<b__1>d.MoveNext() Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

最佳答案

docs 中有一条重要说明解决这个问题:

Authorization handlers are called even if authentication fails.

在您的情况下,身份验证失败但您的 IsParagemNotOnGoingHandlerHandleRequirementAsync 仍在调用。要解决此问题,您只需让您的处理程序实现对丢失的声明更具弹性。这是完整性的示例:

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsParagemNotOnGoingRequirement requirement)
{
    if (!context.User.HasClaim(c => c.Type == ClaimTypes.PrimarySid))
        return Task.CompletedTask;

    ...
}

对于声明的值不可转换为 int 的情况,您可能还想防止 Convert.ToInt32 失败。

关于c# - Asp .Net Core 为什么即使用户未通过身份验证也会调用我的授权处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56806054/

相关文章:

c# - boolean 类型

c# - 为什么双倍面积 = 0;?

C# 7.0 "deconstructor"

c# - 如何全局声明样式并在 uwp 中的应用程序中使用该样式

azure - 上传 Xamarin/Asp-net Core 应用程序的图片和视频

asp.net-core - ViewLocalizer 不返回字符串

angular - ASP.NET Core 2.0 和 Angular 4.3 文件上传有进展

c# - 在 C# 中建模 mongodb 子集合

c# - ASP.NET Core 浏览器链接 `Unable to get property ' 文件'`

.NET Core 3.1 中使用 Fetch API 的 Ajax 调用