使用 API 路由时,在未授权时返回 Http Response 401 而不是重定向到登录页面

Posted

技术标签:

【中文标题】使用 API 路由时,在未授权时返回 Http Response 401 而不是重定向到登录页面【英文标题】:When using an API route, return Http Response 401 instead of redirect to login page when not authorised 【发布时间】:2018-06-04 12:56:05 【问题描述】:

我正在使用 MVC 和 WebAPI 构建一个 ASP.NET Core 2.0 网站,以提供对一系列微服务的访问。如果 WebAPI 控制器要求用户进行身份验证和授权(使用 Authorize 属性),任何未经授权或未登录的用户都会将响应作为 MVC 登录页面的整个 html 返回。

当未经授权的用户访问 API 时,我想在响应中返回 HTTP 状态代码 401 及其相关的错误消息,而不是整个 HTML 页面。

我查看了一些现有问题,并注意到它们要么引用 ASP.NET MVC(例如 SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi),这对 ASP.NET Core 2.0 没有好处。或者他们正在对 Core 1.x 使用 hackaround,这似乎不太正确 (ASP.Net core MVC6 Redirect to Login when not authorised)。

Core 2.0 中是否实施了任何人都知道的适当解决方案?如果没有,有什么想法可以正确实施吗?

作为参考,有一部分控制器作为例子:

[Authorize]
[ApiVersion("1.0")]
[Produces("application/json")]
[Route("api/Vver:apiVersion/Organisation")]
public class OrganisationController : Controller

    ...

    [HttpGet]
    public async Task<IEnumerable<string>> Get()
    
        return await _organisationService.GetAllSubdomains();
    

    ...

以及Statup.cs中的配置:

public void ConfigureServices(IServiceCollection services)

    ...

    // Add API version control
    services.AddApiVersioning(options =>
    
        options.ReportApiVersions = true;
        options.AssumeDefaultVersionWhenUnspecified = true;
        options.DefaultApiVersion = new ApiVersion(1, 0);
        options.ErrorResponses = new DefaultErrorResponseProvider();
    );

    // Add and configure MVC services.
    services.AddMvc()
        .AddJsonOptions(setupAction =>
        
            // Configure the contract resolver that is used when serializing .NET objects to JSON and vice versa.
            setupAction.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
         );

    ...


public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    ...

    app.UseStatusCodePagesWithRedirects("/error/index?errorCode=0");

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
       
        routes.MapRoute(
            name: "default",
            template: "controller=Home/action=Index/id?");

       );

    ...

【问题讨论】:

【参考方案1】:

对于未经授权的请求,有一种简单的方法可以禁止重定向到登录页面。只需在您的ConfigureServices 中添加以下ConfigureApplicationCookie 扩展方法调用:

services.ConfigureApplicationCookie(options =>

    options.Events.OnRedirectToLogin = context =>
    
        context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        return Task.CompletedTask;
    ;
);

或者如果您需要在响应正文中自定义错误消息:

services.ConfigureApplicationCookie(options =>

    options.Events.OnRedirectToLogin = async context =>
    
        context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        await context.Response.WriteAsync("Some custom error message if required");
    ;
);

只要您使用重定向到自定义错误页面的错误代码(UseStatusCodePagesWithRedirects()Configure 方法中调用),您应该为 401 错误添加过滤器。为此,请删除对UseStatusCodePagesWithRedirects 的调用,并使用UseStatusCodePages 扩展方法和跳过未授权代码的重定向:

//app.UseStatusCodePagesWithRedirects("/error/index?errorCode=0");
app.UseStatusCodePages(context =>

    if (context.HttpContext.Response.StatusCode != (int)HttpStatusCode.Unauthorized)
    
        var location = string.Format(CultureInfo.InvariantCulture, "/error/index?errorCode=0", context.HttpContext.Response.StatusCode);
        context.HttpContext.Response.Redirect(location);
    
    return Task.CompletedTask;
);

【讨论】:

这绝对是正确的,感谢您提供额外的UseStatusCodePages() 设置,否则也会导致另外几个小时的悲伤! 是否可以只针对 WebApi 调用而不是页面请求? 当然。在传递的 lambda 中,您可以访问 HttpContext。您可以根据请求 uri 轻松添加条件。 如果您不想屏蔽该网址,您需要返回什么才能继续重定向到登录页面?【参考方案2】:

如果您使用 JWT 通过 ASP.NET Core 2 API 进行身份验证;您可以在为身份验证和 JWT 配置服务时配置未经授权的响应:

        services.AddAuthentication( JwtBearerDefaults.AuthenticationScheme )
                .AddJwtBearer(options => options.Events = new JwtBearerEvents()
                
                    OnAuthenticationFailed = c =>
                    
                        c.NoResult();

                        c.Response.StatusCode = 401;
                        c.Response.ContentType = "text/plain";

                        return c.Response.WriteAsync("There was an issue authorizing you.");
                    
                );

【讨论】:

以上是关于使用 API 路由时,在未授权时返回 Http Response 401 而不是重定向到登录页面的主要内容,如果未能解决你的问题,请参考以下文章

API 返回数据,但在未定义的对象中。这是怎么回事?

未使用 jwt_required 注释时,烧瓶路由请求授权标头

不使用 HTTP 基本身份验证时 HTTP 401 未经授权?

Laravel 护照 oauth 路线总是返回 401 未经授权

从 CDK 对 HTTP API 网关启用 IAM 授权

当使用授权令牌创建存储库“坏凭据”时,git返回401