0

我最初的配置只是 cookie 身份验证,未登录或未授权的重定向有效。然后我添加了 jwt token auth 以与我们应用程序的 api 端一起使用,并且可以正常工作,但是重定向已停止工作。我尝试将架构添加到授权属性,但它没有帮助。  [Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]

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

    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();
            });
       
        }
    }
4

1 回答 1

0

我找到了这个SO答案并对其进行了调整。它基本上检查 UseAuthentication 的结果,如果状态与身份验证相关,如果不是 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);
            }
        }
    }
});

于 2021-08-10T17:57:06.207 回答