在我的ASP.NET核心项目中,我得到了一些带有jwt-authorization的API控制器,如下所示:
[Route("api/v1/[controller]")] public class MyController : Controller { [HttpGet("[action]")] [Authorize(Policy = MyPolicy)] public JsonResult FetchAll() { } }
当访问操作FetchAll()的授权失败时,我想要HttpStatusCode.Forbidden作为响应.相反,Mvc重新路由到帐户/登录?ReturnUrl = [...]
我试图捕获Redirect-Events并返回Forbidden/Unauthorized覆盖Cookie事件无效:
app.UseIdentity(); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = TokenController.DummyKey, ValidateIssuer = false, ValidateAudience = false, ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(0) }; app.UseJwtBearerAuthentication(new JwtBearerOptions { AutomaticAuthenticate = true, AutomaticChallenge = true, TokenValidationParameters = tokenValidationParameters, }); app.UseCookieAuthentication(new CookieAuthenticationOptions() { AutomaticAuthenticate = false, AutomaticChallenge = false, AuthenticationScheme = "BsCookie", CookieName = "access_token", TicketDataFormat = new CustomJwtDataFormat(SecurityAlgorithms.HmacSha256, tokenValidationParameters), Events = new CookieAuthenticationEvents { OnRedirectToLogin = context => { if (context.Request.Path.StartsWithSegments("/api") && context.Response.StatusCode == (int)HttpStatusCode.OK) context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; else context.Response.Redirect(context.RedirectUri); return Task.FromResult(0); }, OnRedirectToAccessDenied = context => { if (context.Request.Path.StartsWithSegments("/api") && context.Response.StatusCode == (int)HttpStatusCode.OK) context.Response.StatusCode = (int)HttpStatusCode.Forbidden; else context.Response.Redirect(context.RedirectUri); return Task.FromResult(0); } }, });
从不调用这两个事件,并且Visual Studio输出显示将返回fetchall Fails和Account/Login:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:6460/api/v1/Lehrer/GetAll application/json Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Successfully validated the token. Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer. Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null). Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'. Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (). Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was forbidden. Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: AuthenticationScheme: Identity.Application was challenged. Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sam.Learning2.Controllers.LehrerController.GetAll (Sam.Learning2) in 49.7114ms Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 121.6106ms 302 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:6460/Account/Login?ReturnUrl=%2Fapi%2Fv1%2FLehrer%2FGetAll
我希望我的API返回401/403而不是重定向到Login - 如果以上代码不起作用,我该如何实现?
ASP.NET Core 2.0中的授权稍有变化.下面的答案仅对ASP.NET Core 1.x有效.对于ASP.NET Core 2.0,请参阅此答案和此GitHub公告.
你似乎忘记的是,app.UseIdentity()
它还注册了cookie中间件.
var options = app.ApplicationServices.GetRequiredService>().Value; app.UseCookieAuthentication(options.Cookies.ExternalCookie); app.UseCookieAuthentication(options.Cookies.TwoFactorRememberMeCookie); app.UseCookieAuthentication(options.Cookies.TwoFactorUserIdCookie); app.UseCookieAuthentication(options.Cookies.ApplicationCookie);
并且ASP.NET Core Identity 为cookie()中间件设置了AutomaticChallange
to (参见源代码).因此重定向到.您需要在Identity中禁用此选项.true
ApplicationCookie
/Account/Login?ReturnUrl
services.AddIdentity(options => { options.Cookies.ApplicationCookie.AutomaticChallenge = false; });
如果你真的想拥有Identity的Auth(登录网页)和JWT,你需要根据网址注册中间件.所以ie app.UseIdentity()
只注册了非api urls,Jwt中间件只注册了以urls开头的网址/api
.
你可以用.MapWhen
(docs)做到这一点.
app.MapWhen(context => !context.Request.Path.StartsWith("/api"), branch => { branch.UseIdentity(); });
现在branch.UseIdentity()
只会用于不开头的URL,这些URL /api
通常是您/Account/Login
需要重定向的MVC视图.
我只是使用Barry Dorrans Asp Net 授权工作室
在ConfigureServices
我只是添加services.AddAuthorization();
.
并Configure
添加此代码:
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationScheme = "Cookie", LoginPath = new PathString("/Account/Login/"), AccessDeniedPath = new PathString("/Account/Forbidden/"), AutomaticAuthenticate = true, AutomaticChallenge = true, Events = new CookieAuthenticationEvents() { OnRedirectToLogin = (ctx) => { if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200) { ctx.Response.StatusCode = 401; } else ctx.Response.Redirect(ctx.RedirectUri); return Task.CompletedTask; }, OnRedirectToAccessDenied = (ctx) => { if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200) { ctx.Response.StatusCode = 403; } else { ctx.Response.Redirect(ctx.RedirectUri); } return Task.CompletedTask; } } }
在Mvc重新路由到帐户/登录?ReturnUrl = [...]并在API中,您将获得401或403.