C# 使Web API身份验证返回401,而不是重定向到登录页面

C# 使Web API身份验证返回401,而不是重定向到登录页面,c#,asp.net,asp.net-mvc,authentication,asp.net-web-api,C#,Asp.net,Asp.net Mvc,Authentication,Asp.net Web Api,我在WebMVC中有带OWIN身份验证的WebAPI。 我正在Web.Config中为我的Web MVC使用,因此它将重定向到登录页面 <authentication mode="Forms"> <forms name="WEB.AUTH" loginUrl="~/login" domain="" protection="All" timeout="43200" path="/" requireSSL="false" slidingExpiration="tr

我在WebMVC中有带OWIN身份验证的WebAPI。 我正在Web.Config中为我的Web MVC使用
,因此它将重定向到登录页面

<authentication mode="Forms">
    <forms name="WEB.AUTH" loginUrl="~/login" domain="" protection="All" 
    timeout="43200" path="/" requireSSL="false" slidingExpiration="true" />
</authentication>

确保将
app.Map()
放在Web Api配置行之后。否则,它将给MVC应用程序带来错误。

创建一个自定义的
AuthorizeAttribute

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Unauthorized");
    }
}
如果将来跳过web.config内容并使用owin设置身份验证,您可以在
Startup.cs
中执行以下操作:

var provider = new CookieAuthenticationProvider();
var originalHandler = provider.OnApplyRedirect;
provider.OnApplyRedirect = context =>
{
    if (!context.Request.Uri.LocalPath.StartsWith(VirtualPathUtility.ToAbsolute("~/api")))
    {
        context.RedirectUri = new Uri(context.RedirectUri).PathAndQuery;
        originalHandler.Invoke(context);
    }
};

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    CookieName = FormsAuthentication.FormsCookieName,
    LoginPath = new PathString("/Account/LogOn"),
    ExpireTimeSpan = TimeSpan.FromMinutes(240),
    Provider = provider
});

这就是我的工作

创建自定义属性:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class NoRedirectAuthorizeAttribute : AuthorizeAttribute
{        
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
    }
}
使用控制器中的属性:

    [HttpDelete]
    [NoRedirectAuthorizeAttribute(Roles = "Admin")]
    [Route("api/v3/thingstodelete/{id=id}")]
    public IHttpActionResult DeleteThingToDelete(Guid id)
    {
      //delete code
    }

下面是重写的HandleUnauthorizedRequest方法。因此,我们不发送重定向(304)到登录页面,而是发送禁止的(403)HTTP状态代码。

为了更改IIS基于URL定义的约定的行为方式,您希望将OWIN管道分支。您可以使用
iaapplicationbuilder.Map
来实现这一点。假设静态
配置

public void Configure(IApplicationBuilder app)
{
    ...
    app.Map("/api", HandleWebApiRequests);
    ...
}

private static void HandleWebApiRequests(IApplicationBuilder app)
{
    app.UseWebApi(config);
}
Map
方法基于以
“/api”
开头的URL将管道分支到
handleWebAppirequests
方法


这将导致401错误的行为与预期的一样,只返回401而不重定向。

我需要配置StatusCodePage中间件以避免重定向

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.UseStatusCodePages();
    ...
}

在.NET Core中,我这样解决了它,Startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.Cookie.SameSite = SameSiteMode.Strict;
                options.Cookie.Name = "AuthCookie";
                options.Events.OnRedirectToAccessDenied = UnAuthorizedResponse;
                options.Events.OnRedirectToLogin = UnAuthorizedResponse;
            })
    ....
    }

    internal static Task UnAuthorizedResponse(RedirectContext<CookieAuthenticationOptions> context)
    {
        context.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
        return Task.CompletedTask;
    }
public void配置服务(IServiceCollection服务)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(选项=>
{
options.Cookie.SameSite=SameSiteMode.Strict;
options.Cookie.Name=“AuthCookie”;
options.Events.OnRedirectToAccessDenied=未经授权的响应;
options.Events.OnRedirectToLogin=未经授权的响应;
})
....
}
内部静态任务未授权响应(重定向上下文)
{
context.Response.StatusCode=(int)HttpStatusCode.Unauthorized;
返回Task.CompletedTask;
}

我很难解决这个问题,我想出了一种方法,只有在我没有在标题中找到用于自定义手动授权WebApi的令牌时,才能执行重定向。这是我的设置(注意Provider对象和OnApplyRedirect操作)


默认情况下,WEPAPI首先检查cookie,但对于从cookie更改为jwt,我使用下面的属性

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

上面的控制器

对我不起作用。然而,我找到了解决办法。请查看我编辑的帖子。
    app.UseCookieAuthentication(new CookieAuthenticationOptions
   {
     AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
     LoginPath = new PathString("/Account/Login"),
     ExpireTimeSpan = TimeSpan.FromMinutes(30),
     Provider =  new CookieAuthenticationProvider
      {
        OnApplyRedirect = (ctx) => {
            var token = HttpContext.Current.Request.Headers.Get("X-User-Token");
            if (token == null) ctx.Response.Redirect(ctx.RedirectUri);
         }
      }
   });  
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]