如何从ASP.NET Core webapi中删除重定向并返回HTTP 401?

时间:2015-09-30 09:53:32

标签: asp.net asp.net-web-api authorization asp.net-core

根据this question的答案,我默认添加了对所有内容的授权,使用以下代码:

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;
  });
}

但是,当有人试图访问未经授权的内容时,会返回一个(看似默认的)重定向网址(http://foo.bar/Account/Login?ReturnUrl=%2Fapi%2Ffoobar%2F)。

我希望它仅返回HTTP 401,而不是重定向。

如何在ASP.NET 5中为WebAPI执行此操作?

6 个答案:

答案 0 :(得分:21)

我在Angular2 + ASP.NET Core应用程序中遇到过这个问题。我设法通过以下方式修复它:

if word.isdigit() and len(word) == 10:

如果这对您不起作用,您可以尝试使用以下方法:

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

Asp.Net Core 2.0更新

现在可以通过以下方式配置Cookie选项:

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);
       }
    };
    // ...
}

答案 1 :(得分:5)

通过网址,您会被重定向到我假设您正在使用Cookie身份验证。

应该通过将LoginPath的{​​{1}}属性设置为null或由其中一个用户清空为described来获得所需的结果。

CookieAuthenticationOptions

当时可能正在工作但是不再工作(因为this更改了)。

我已为此提交bug on GitHub

一旦修复后我会更新答案。

答案 2 :(得分:1)

请注意,只有当您想使用自己的身份验证机制时,才应使用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

中测试

答案 3 :(得分:1)

如果它有帮助,下面是我的答案 - 使用dotnet 1.0.1

它基于Darkseal的答案,除了我必须添加行ctx.Response.WriteAsync()来停止重定向到默认的401 URL(帐户/登录)

        // 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();
    }

答案 4 :(得分:1)

我有类似的问题。 我通过手动服务解决了这个问题。

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 core 2.0,IdentityServer 4和aspnet标识。

答案 5 :(得分:0)

Startup中使用此代码:

services.ConfigureApplicationCookie(options =>
            {
                options.LoginPath = $"/Account/Login";
                options.LogoutPath = $"/Account/Logout";
                options.AccessDeniedPath = $"/Account/AccessDenied";
                options.Events = new CookieAuthenticationEvents()
                {
                    OnRedirectToLogin = (ctx) =>
                    {
                        if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
                            ctx.Response.StatusCode = 401;
                        return Task.CompletedTask;
                    },
                    OnRedirectToAccessDenied = (ctx) =>
                    {
                        if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
                            ctx.Response.StatusCode = 403;
                        return Task.CompletedTask;
                    }
                };
            });