我的原始配置只是cookie身份验证,并且未登录或未授权的重定向工作。然后我添加了jwt令牌授权,以便与应用程序的api端一起使用,这可以工作,但是重定向已经停止工作。我尝试将模式添加到authorize属性中,但是没有帮助。[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
我尝试处理事件。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();
});
}
}
我找到了这个答案并改编了它。它基本上检查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);
}
}
}
});