web-dev-qa-db-ja.com

ASP.NET Coreで302ではなく401を返す方法は?

ユーザーがログインしていないときにASP.NET Core Identityが401を返すようにしようとしています。メソッドに[Authorize]属性を追加し、401を返す代わりに302を返します。 services.Configureおよびapp.UseCookieAuthenticationLoginPathnullまたはPathString.Emptyに設定するなど、多数の提案が機能しているようには見えません。

24
Eric B

ASP.NET Core 2.xの時点:

services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = 401;    
        return Task.CompletedTask;
    };
});
45

要求ヘッダーにX-Requested-With:XMLHttpRequestが含まれる場合、ステータスコードは302ではなく401になります

private static bool IsAjaxRequest(HttpRequest request)
    {
        return string.Equals(request.Query["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal) ||
            string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.Ordinal);
    }

GitHubを参照してください: https://github.com/aspnet/Security/blob/5de25bb11cfb2bf60d05ea2be36e80d86b38d18b/src/Microsoft.AspNetCore.Authentication.Cookies/Events/CookieAuthenticationEvents.cs#L40-L52

15
kroatti

asp.net mvcコアの場合このインスタンスを使用

 services.ConfigureApplicationCookie(options =>
        {
            options.LoginPath = new PathString("/Account/Login");
            options.LogoutPath = new PathString("/Account/Logout");

            options.Events.OnRedirectToLogin = context =>
            {
                if (context.Request.Path.StartsWithSegments("/api")
                    && context.Response.StatusCode == StatusCodes.Status200OK)
                {
                    context.Response.Clear();
                    context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    return Task.CompletedTask;
                }
                context.Response.Redirect(context.RedirectUri);
                return Task.CompletedTask;
            };
        });
12
Francis Ofosu
services.Configure<IdentityOptions>(options =>
{
   options.Cookies.ApplicationCookie.LoginPath = new PathString("/");
   options.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents()
   {
      OnRedirectToLogin = context =>
      {
         if (context.Request.Path.Value.StartsWith("/api"))
         {
            context.Response.Clear();
            context.Response.StatusCode = 401;
            return Task.FromResult(0);
         }
         context.Response.Redirect(context.RedirectUri);
         return Task.FromResult(0);
      }
   };
});

ソース:

https://www.illucit.com/blog/2016/04/asp-net-5-identity-302-redirect-vs-401-unauthorized-for-api-ajax-requests/

11
Mark Perry

asp.netコアユニットテスト を詳しく調べたところ、ようやく実用的なソリューションが見つかりました。 services.AddIdentityへの呼び出しに次を追加する必要があります

services.AddIdentity<ApplicationUser, IdentityRole>(o => {
    o.Cookies.ApplicationCookie.AutomaticChallenge = false;
});
5
Eric B

Identity = Cookie認証を使用するASP.NET Core 3.x(プレビュー)の場合、これがトリックでした:

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<IdentityContext>()
    .AddDefaultTokenProviders()
    .AddRoles<IdentityRole>();

services.ConfigureApplicationCookie(options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.Headers["Location"] = context.RedirectUri;
        context.Response.StatusCode = 401;
        return Task.CompletedTask;
    };
});

これは、さまざまなバリエーションで至る所に見られます。しかし、ここでの本質的なポイントは、ConfigureApplicationCookieを指定する必要があることです[〜#〜] after [〜#〜]AddIdentity。それは「悲しい」ですが、本当です。これは SOの答え 最終的に暗闇の中で光をもたらしました。

私は1日以上頭を擦って、さまざまなバリエーションを試しました:

  • Authorize属性をオーバーライドします(3.xでオーバーライドすることはもうありません)
  • Cookieでoptions.Cookie.EventTypeを指定する(実行時エラー)
  • options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme(JWTベアラーはログインページにリダイレクトしないと言われていました)
  • そしてもちろんApplicationCookieを設定します(ただし、AddIdentityへの呼び出しの前に動作しません。

それはすべてうまくいきませんでした。しかし、上記の答えで、最終的に401 UnAuthorizedが返されました(これはUnAuthenticatedであるはずです)

0
Bernoulli IT

ASP.NET Core 2.2.0の私にとっては、これだけが機能しました:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(
        options =>
        {
            options.LoginPath = new PathString("/Account/Login");
            options.LogoutPath = new PathString("/Account/Logout");

            options.Events.OnRedirectToLogin = context =>
            {
                if (context.Request.Path.StartsWithSegments("/api")
                    && context.Response.StatusCode == StatusCodes.Status200OK)
                {
                    context.Response.Clear();
                    context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    return Task.CompletedTask;
                }
                context.Response.Redirect(context.RedirectUri);
                return Task.CompletedTask;
            };
        }
    );
0
SirGordon