提问者:小点点

AccessDeniedPath和LoginPath重定向在添加JWT身份验证后停止工作


我最初的配置只是cookie身份验证,重定向为未登录或未授权工作。然后我添加了jwt token auth以用于我们应用程序的api端,这是可行的,但是重定向已经停止工作。我尝试将模式添加到授权attrib,但没有帮助。

我尝试处理Event. OnReDirectToAccessDened事件,但当我添加jwt支持(AddJwtBeler并将架构添加到默认策略)时,它不会触发。

    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.AddCors(policy =>
            {
                policy.AddPolicy("OpenCorsPolicy", opt =>
                    opt.AllowAnyOrigin()
                    .AllowAnyHeader()
                    .AllowAnyMethod());
            });

            services.AddTransient<IUserManager, UserManager>();

            var tokenValidationParams = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JWTSecret"))),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                RequireSignedTokens = true,

                ClockSkew = TimeSpan.FromMinutes(1)
            };

            // adding the token settings so that hey are DI-able
            services.AddSingleton<TokenValidationParameters>(tokenValidationParams);

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.Strict;
            });

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, x =>
                {
                    x.LoginPath = new PathString("/Account/Login");
                    x.ExpireTimeSpan = TimeSpan.FromMinutes(Configuration.GetValue<int>("CookieExpiry"));
                    x.AccessDeniedPath = new PathString("/Account/Login");
                    x.SlidingExpiration = true;

                    //x.Events.OnRedirectToAccessDenied = ReplaceRedirector(HttpStatusCode.Forbidden, x.Events.OnRedirectToAccessDenied);
                    //x.Events.OnRedirectToLogin = ReplaceRedirector(HttpStatusCode.Unauthorized, x.Events.OnRedirectToLogin);
                })
                .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, x =>
                {
                    x.RequireHttpsMetadata = false;
                    x.SaveToken = true;
                    x.TokenValidationParameters = tokenValidationParams;
                })
                ;

            static Func<RedirectContext<CookieAuthenticationOptions>, Task> ReplaceRedirector(HttpStatusCode statusCode, Func<RedirectContext<CookieAuthenticationOptions>, Task> existingRedirector) =>
                context => {
                    context.Response.Redirect(context.RedirectUri + "&Extra=Foo");
                    System.Diagnostics.Debug.WriteLine(statusCode);
                    return Task.CompletedTask;
                //return existingRedirector(context);
            };

            services.AddAuthorization(options =>
            {
                // setting up that the default authorize can be either cookie or token
                var defaultAuthorizationPolicyBuilder =
                    new AuthorizationPolicyBuilder(
                        CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
                defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
                options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
            });

            services.AddMvc(); //.AddJsonOptions(jsonOptions => jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null);

            services.AddRazorPages(options =>
            {
                // you can set the authentication at the folder level
                options.Conventions.AuthorizeFolder("/");
                // you can set authenication for a single page
                options.Conventions.AllowAnonymousToPage("/Error");
                // you can set in the razor page     [AllowAnonymous] like on index

                /*
                    options.Conventions.AuthorizePage("/Contact");
                    options.Conventions.AuthorizeFolder("/Private");
                    options.Conventions.AllowAnonymousToPage("/Private/PublicPage");
                    options.Conventions.AllowAnonymousToFolder("/Private/PublicPages");
                 */
            });
        }

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

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapControllers();
            });
       
        }
    }

共1个答案

匿名用户

我找到了这个SO的答案并对其进行了调整。它基本上检查了UseAuthentication的结果,如果状态与auth相关,如果它不是api调用,则触发cookie方案的挑战和禁止处理程序。我正在检查不记名令牌的存在,因为api调用可能根本没有它,而不是过期或未经授权。正如最初的答案所说,这必须在身份验证确定后添加到链中。

app.UseAuthentication();

app.Use(async (context, next) =>
{
    await next();
    if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403)
    {
        //var bearerAuth = context.Request.Headers["Authorization"]
        //.FirstOrDefault()?.StartsWith("Bearer ") ?? false;
        var isAPI = context.Request.Path.Value.Contains("/api/", StringComparison.OrdinalIgnoreCase);
        if (!isAPI)
        {
            if (context.Response.StatusCode == 401)
            {
                await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            }
            else if (context.Response.StatusCode == 403)
            {
                await context.ForbidAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            }
        }
    }
});