web-dev-qa-db-ja.com

ASP.Net Core-API認証エラーのリダイレクトなし

私のASP.NET Coreプロジェクトでは、次のようなjwt-authorizationのAPIコントローラーをいくつか取得しました。

[Route("api/v1/[controller]")]
public class MyController : Controller
{
  [HttpGet("[action]")]
  [Authorize(Policy = MyPolicy)]
  public JsonResult FetchAll()
  {
  }
}

アクションFetchAll()にアクセスするための認証が失敗した場合、HttpStatusCode.Forbiddenを応答として使用します。代わりに、MvcはAccount/Login?ReturnUrl = [...]に転送します。

Redirect-Eventsをキャプチャし、Cookie Eventsを無効にしてForbidden/Unauthorizedを無効に戻そうとしました。

  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が失敗し、代わりにアカウント/ログインが返されることを示します。

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を返すようにしたいのですが、上記のコードが機能しない場合、どうすればこれを実現できますか?

18
Sam

ASP.NET Core 2.xを更新する

ASP.NET Core 2.0では承認が少し変更されました。以下の答えは、ASP.NET Core 1.xにのみ有効です。 ASP.NET Core 2.0については、この answer およびこの GitHubアナウンスメント を参照してください。

ASP.NET Core 1.x

あなたが忘れていると思われるのは、app.UseIdentity()cookieミドルウェアを登録する です。

_var options = app.ApplicationServices.GetRequiredService<IOptions<IdentityOptions>>().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はAutomaticChallangetrueにCookie(ApplicationCookie)ミドルウェアに設定します( sourceを参照 )。したがって、_/Account/Login?ReturnUrl_へのリダイレクト。 Identityでこのオプションを無効にする必要があります。

_services.AddIdentity(options =>
{
    options.Cookies.ApplicationCookie.AutomaticChallenge = false;
});
_

reallyIdentity's Auth(Webページへのログイン)とJWTが必要な場合は、URLに基​​づいてミドルウェアを登録する必要があります。つまり、app.UseIdentity()は非API URLにのみ登録され、Jwtミドルウェアは_/api_で始まるURLにのみ登録されます。

_.MapWhen_( docs )でそれを行うことができます。

_app.MapWhen(context => !context.Request.Path.StartsWith("/api"), branch => 
{
    branch.UseIdentity();
});
_

branch.UseIdentity()は、_/api_で始まらないURLにのみ使用されます。これは通常、_/Account/Login_へのリダイレクトが必要なMVCビューです。

18
Tseng

Barry Dorrans Asp Netを使用します Authorization Workshop

ConfigureServicesservices.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ではAccount/Login?ReturnUrl = [...]に再ルーティングし、APIでは401または403を取得します。

9
akaco

MicrosoftのWeb APIスタックは、すぐに使用できるようにセットアップされています。ソリューションはクライアント側にあります。

このヘッダーをクライアントリクエストに追加します。

'X-Requested-With': 'XMLHttpRequest'

Web APIはそのヘッダーを探します。要求が認証されていない場合、存在する場合は401を返します。ヘッダーがない場合、ログインページへのリダイレクトを返します。

こちらをご覧ください https://github.com/aspnet/Security/issues/1394#issuecomment-326445124

クライアントを変更できない場合にのみ、Cookieイベントでより複雑なコードが必要になると思います。

0
RichardHowells