web-dev-qa-db-ja.com

ASP.NET Core Web APIからリダイレクトを削除してHTTP 401を返す方法は?

この質問 の回答に続いて、次のコードを使用して、デフォルトですべてに承認を追加しました。

public void ConfigureServices(IServiceCollection aServices)
{
  aServices.AddMvc(options =>
  {
     var lBuilder = new AuthorizationPolicyBuilder().RequireAuthenticatedUser();

     var lFilter = new AuthorizeFilter(lBuilder.Build());
     options.Filters.Add(lFilter);
   });

   aServices.AddMvc();
}

public void Configure(IApplicationBuilder aApp, IHostingEnvironment aEnv, ILoggerFactory aLoggerFactory)
{
  aApp.UseCookieAuthentication(options =>
  {
    options.AuthenticationScheme = "Cookies";
    options.AutomaticAuthentication = true;
  });
}

しかし、誰かが不正なものにアクセスしようとすると、(デフォルトのように見える)リダイレクトURL( http://foo.bar/Account/Login?ReturnUrl=%2Fapi%2Ffoobar%2F )が返されます。

リダイレクトではなく、HTTP 401のみを返すようにしたい。

ASP.NET 5でWebAPIを使用するにはどうすればよいですか?

17
Geerten

Angular2 + ASP.NET Coreアプリケーションでこの問題が発生しました。私はそれを次の方法で修正することができました:

services.AddIdentity<ApplicationUser, IdentityRole>(config =>   {
    // ...
    config.Cookies.ApplicationCookie.AutomaticChallenge = false;
    // ...
});

これがうまくいかない場合は、代わりに次の方法を試すことができます。

services.AddIdentity<ApplicationUser, IdentityRole>(config =>   {
    // ...
    config.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents
    {
       OnRedirectToLogin = ctx =>
       {
           if (ctx.Request.Path.StartsWithSegments("/api")) 
           {
               ctx.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
               // added for .NET Core 1.0.1 and above (thanks to @Sean for the update)
               ctx.Response.WriteAsync("{\"error\": " + ctx.Response.StatusCode + "}");
           }
           else
           {
               ctx.Response.Redirect(ctx.RedirectUri);
           }
           return Task.FromResult(0);
       }
    };
    // ...
}

Asp.Net Core 2.0の更新

Cookieオプションは、次のように構成されています。

services.ConfigureApplicationCookie(config =>
            {
                config.Events = new CookieAuthenticationEvents
                {
                    OnRedirectToLogin = ctx => {
                        if (ctx.Request.Path.StartsWithSegments("/api"))
                        {
                            ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                        }
                        else {
                            ctx.Response.Redirect(ctx.RedirectUri);
                        }
                        return Task.FromResult(0);
                    }
                };
            });
25
Darkseal

リダイレクトされるURLによって、Cookie認証を使用していると思います。

LoginPathCookieAuthenticationOptionsプロパティをnullまたは空に設定して目的の結果を得る必要があります記述 ユーザーの1人。

app.UseCookieAuthentication(options =>
        {
            options.LoginPath = "";
        });

それはおそらく当時は機能していましたが、機能しなくなっていますthis の変更のため)。

GitHubのバグ を提出しました。

修正されたら回答を更新します。

5
mbudnik

LoginPath = ""またはnullの設定は、バージョン1.1.0.0では機能しなくなりました。だからこれが私がしたことです:

app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            ExpireTimeSpan = TimeSpan.FromDays(150),
            AuthenticationScheme = options.Cookies.ApplicationCookie.AuthenticationScheme,
            Events = new CookieAuthenticationEvents
            {
                OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync,
                OnRedirectToLogin = async (context) => context.Response.StatusCode = 401,
                OnRedirectToAccessDenied = async (context) => context.Response.StatusCode = 403
            },
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
        });
4
mode777

同様の問題がありました。サービスを手動で追加することでこれを解決しました。

ConfigureServicesメソッド:

    services.AddTransient<IUserStore<User>, UserStore<User, IdentityRole, ApplicationDbContext>>();   
    services.AddTransient<IPasswordHasher<User>, PasswordHasher<User>>();
    services.AddTransient<IUserValidator<User>, UserValidator<User>>();
    services.AddTransient<ILookupNormalizer, UpperInvariantLookupNormalizer>();
    services.AddTransient<IPasswordValidator<User>, PasswordValidator<User>>();
    services.AddTransient<IdentityErrorDescriber, IdentityErrorDescriber>();
    services.AddTransient<ILogger<UserManager<User>>, Logger<UserManager<User>>>();
    services.AddTransient<UserManager<User>>();

    services.AddMvcCore()
    .AddJsonFormatters()
    .AddAuthorization();


    services.AddCors(options=> {
    options.AddPolicy("AllowAllHeaders", (builder) => {
        builder.WithOrigins("*").AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().WithExposedHeaders("WWW-Authenticate"); ;
    });
});


    services.AddAuthentication(options=> {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;
        options.ApiName = "api1";
        options.ApiSecret = "secret";
    });

メソッドの構成:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("AllowAllHeaders");
    app.UseAuthentication();
    app.UseMvc();

}

私はaspnetコア2.0、IdentityServer 4、およびaspnetidentityを使用しています。

それが役立つ場合は、以下が私の答えです-dotnet 1.0.1

デフォルトの401URL(アカウント/ログイン)へのリダイレクトを停止するためにctx.Response.WriteAsync()行を追加する必要があったことを除いて、Darksealの回答に基づいています。

        // Adds identity to the serviceCollection, so the applicationBuilder can UseIdentity
        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {                
            //note: this has no effect - 401 still redirects to /Account/Login!
            //options.Cookies.ApplicationCookie.LoginPath = null;

            options.Cookies.ApplicationCookie.Events = new CookieAuthenticationEvents
            {
                OnRedirectToLogin = ctx =>
                {
                    //for WebApi: prevent aspnet core redirecting to 'Account/Login' on a 401:
                    if (ctx.Request.Path.StartsWithSegments("/api"))
                    {
                        ctx.RedirectUri = null;
                        ctx.Response.WriteAsync("{\"error\": " + ctx.Response.StatusCode + "}");
                    }
                    else
                    {
                        ctx.Response.Redirect(ctx.RedirectUri);
                    }
                    return Task.FromResult(0);
                }
            };
        })
            .AddDefaultTokenProviders();
    }
1
Sean

CookieAuthenticationプロバイダーをバイパスするなど、独自の認証メカニズムを使用する場合にのみ、Identityを使用しないでください。ほとんどの場合はそうではありません。

デフォルトのIdentityプロバイダーはバックグラウンドでCookieAuthenticationOptionsを使用しますが、以下のように構成できます。

services.AddIdentity<ApplicationUser, IdentityRole>(o =>
 {
     o.Password.RequireDigit = false;
     o.Password.RequireUppercase = false;
     o.Password.RequireLowercase = false;
     o.Password.RequireNonAlphanumeric = false;
     o.User.RequireUniqueEmail = true;

     o.Cookies.ApplicationCookie.LoginPath = null; // <-----
 })
 .AddEntityFrameworkStores<ApplicationDbContext>()
 .AddDefaultTokenProviders(); 

バージョン1.0.0でテスト済み

1
amd