防止在 asp.net 5 (vNext) 中对预检 OPTIONS 请求进行基于令牌的授权

Posted

技术标签:

【中文标题】防止在 asp.net 5 (vNext) 中对预检 OPTIONS 请求进行基于令牌的授权【英文标题】:Prevent token based authorization of preflight OPTIONS requests in asp.net 5 (vNext) 【发布时间】:2016-04-09 08:00:26 【问题描述】:

我在 asp.net 5 (RC1) 中有一个几乎可以工作的 OAuth2 实现。我的解决方案基于 Mark Hughes 在Token Based Authentication in ASP.NET 5 (vNext) 中给出的代码,非常棒。

我的问题是我的设置正在使用 CORS 请求,并且几乎每个请求之前都有一个 OPTIONS 请求。即使我只将 Authorize 属性应用于 GetAll 控制器操作/方法,如下所示,前面的 OPTIONS 请求也是授权的。

[Route("api/[controller]")]
public class TextController : Controller

    [HttpGet]
    [Authorize("Bearer", Roles = "admin")]
    public IEnumerable<string> GetAll()
    
        return _repository.GetAll;
    

    ...

startup.cs 中的授权服务设置如下:

services.AddAuthorization(auth =>
        
            auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
                .RequireAuthenticatedUser().Build());
        );

有什么方法可以改变授权中间件的行为以跳过对 OPTIONS 请求的授权?

注意:

我尝试创建自己的授权属性,但由于某种原因,IsAuthenticated 始终评估为 false,就好像在到达此代码时授权尚未发生:

public class BearerAuthorizationAttribute : Attribute, IAuthorizationFilter

    private readonly string Role;
    public BearerAuthorizationAttribute(string Role = null)
    
        this.Role = Role;
    
    [Authorize("Bearer")]
    public void OnAuthorization(Microsoft.AspNet.Mvc.Filters.AuthorizationContext context)
    
        string meth = context.HttpContext.Request.Method;
        if (meth != "OPTIONS")
        

            if (!context.HttpContext.User.Identity.IsAuthenticated)
            
                context.Result = new ContentResult()  Content = "Unauthorized", StatusCode = 401 ;
                return;
            
            if (Role != null && !context.HttpContext.User.IsInRole(Role))
            
                context.Result = new ContentResult()  Content = "Unauthorized, role level insufficient", StatusCode = 401 ;
                return;
            
        

    

【问题讨论】:

【参考方案1】:

我终于想出了如何解决我的问题。在我的 Startup.cs 中,我使用的是 services.AddCors,如下所示:

// Create CORS policies
services.AddCors(options =>

    // Define one or more CORS policies
    options.AddPolicy("AllowSpecificOrigin",
        builder =>
        
            builder.WithOrigins(Configuration.Get<string[]>("AppSettings:AllowedOrigins")) // TODO: revisit and check if this can be more strict and still allow preflight OPTION requests
                        .AllowAnyMethod() 
                        .AllowAnyHeader();
        
    );
);
// Apply CORS policy globally
services.Configure<MvcOptions>(options =>

    options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
);

事实证明这只是部分起作用。

解决方案对我来说是改用app.UseCors,即删除上面的代码并这样做:

app.UseCors(builder =>

    builder.WithOrigins(Configuration.Get<string[]>("AppSettings:AllowedOrigins")) // TODO: revisit and check if this can be more strict and still allow preflight OPTION requests
        .AllowAnyMethod()
        .AllowAnyHeader();
);

当使用 app.UseCors 时,我得到了完全正常的 CORS 处理,这会在 OPTIONS 请求被授权之前弹回它们。

该解决方案的灵感来自CORS is not working in web api with OWIN authentication。

【讨论】:

以上是关于防止在 asp.net 5 (vNext) 中对预检 OPTIONS 请求进行基于令牌的授权的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 5 (vNext) - 获取配置设置

ASP.NET 5 (vNext) 中的身份验证

在 asp.net 5/vnext 上的磁盘上没有 dll 的代码合同

如何在 ASP.NET 5 MVC 6 (vNext) 中定义 Identity 的密码规则?

ASP.NET 5 - 启动 ASP.NET vNext 项目

在 ASP.NET 5 (vNext) MVC 6 中实现自定义路由器