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

Jac*_*kal 4 c# asp.net-core

我有一个问题,如果我手动转到登录页面之后的页面,我的策略句柄之一会出现异常,因为它找不到索赔。

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

[Authorize("scheme"), Policy = "policy"]
Run Code Online (Sandbox Code Playgroud)

这是我的整个启动代码

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?}");
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的handler,每个handler基本都是一样的。要求很简单,身体里什么也没有。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是例外

处理请求时发生未处理的异常。NullReferenceException:未将对象引用设置为对象的实例。IsParagemNotOnGoingHandler.cs 第 27 行中的 NoPaper.Policies.IsParagemNotOnGoingHandler.HandleRequirementAsync(AuthorizationHandlerContext 上下文、IsParagemNotOnGoingRequirement 要求)

堆栈查询 Cookie 标头 NullReferenceException:未将对象引用设置为对象的实例。IsParagemNotOnGoingHandler.cs 中的 NoPaper.Policies.IsParagemNotOnGoingHandler.HandleRequirementAsync(AuthorizationHandlerContext 上下文,IsParagemNotOnGoingRequirement 要求) + var registoId = Convert.ToInt32(context.User.FindFirst(c => c.Type == ClaimTypes.PrimarySid).Value); Microsoft.AspNetCore.Authorization.AuthorizationHandler.HandleAsync(AuthorizationHandlerContext上下文) Microsoft.AspNetCore.Authorization.DefaultAuthorizationService.AuthorizeAsync(ClaimsPrincipal用户,对象资源,IEnumerable要求) Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthorizeAsync(AuthorizationPolicy策略,AuthenticateResult认证结果, HttpContext 上下文,对象资源) 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 上下文) Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext 上下文) 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。调用(HttpContext 上下文)

Kir*_*kin 7

文档中有一个重要的注释解决了这个问题:

即使身份验证失败,也会调用授权处理程序。

在您的情况下,身份验证已失败,但您的IsParagemNotOnGoingHandler仍被HandleRequirementAsync调用。要解决该问题,您只需使处理程序实现对丢失的声明更具弹性即可。下面是一个完整性示例:

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

Convert.ToInt32对于声明的值不可转换为int.