JWT和Windows身份验证的ASP.Net Core 2.0混合身份验证不接受凭据

时间:2018-06-27 01:51:07

标签: c# authorization asp.net-core-2.0 authorize-attribute

我已经在asp.net core 2.0中创建了API,在其中我正在使用混合模式身份验证。对于某些控制器JWT和某些使用Windows身份验证的人。

我对使用JWT授权的控制器没有任何问题。但是对于要使用Windows身份验证的控制器,会无限地提示我chrome的用户名和密码对话框。

这里是我要使用Windows身份验证而不是JWT的示例控制器代码。

[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Windows")]
public class TestController : Controller
{
    [HttpPost("processUpload")]
    public async Task<IActionResult> ProcessUploadAsync(UploadFileModel uploadFileModel)
    {

    }
}

我的配置服务代码

public void ConfigureServices(IServiceCollection services)
{
     services.AddAuthentication(options =>
     {
        options.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
     })
     .AddJwtBearer("Bearer", options =>
     {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = false,       
            ValidateIssuer = false,  
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("blahblahKey")),
            ValidateLifetime = true, //validate the expiration and not before values in the token
            ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
        };
     });

     // let only my api users to be able to call 
     services.AddAuthorization(auth =>
     {
        auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme‌​)
            .RequireClaim(ClaimTypes.Name, "MyApiUser").Build());
     });

     services.AddMvc();
}

我的配置方法。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseCors("CorsPolicy");

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseAuthentication(); //needs to be up in the pipeline, before MVC
    app.UseMvc();
}

赞赏您的建议和帮助。

更新:到目前为止,我一直在chrome上调试代码。但是,当我使用IE 11时,上面的代码正在运行,没有任何问题。

这可能是Chrome的CORS问题,而不是飞行前问题?

谢谢

3 个答案:

答案 0 :(得分:15)

您需要确保在尝试使用Windows Auth时设置Authorization: Bearer <JWT_token> HTTP标头。这里的关键是“ Windows Auth”的实际工作方式。让我们看看它如何与浏览器一起工作。

我们称其为“正常流程”:

  1. 您在浏览器中导航到http://example.com/api/resource
  2. 您的浏览器暂时向http://example.com/api/resource发送HTTP GET请求,而没有任何 Authorization HTTP标头(匿名请求);
  3. Web服务器(或WebAPI本身)接收到一个请求,发现没有 Authorization 标头,并用 {{ 1}} 设置了HTTP标头(“走开,没有匿名访问。只欢迎'NTLM'或'Negotiate'家伙!“ );
  4. 浏览器收到一个401 Not Authorized响应,发现该请求是匿名的,查找 WWW-Authenticate: NTLM,Negotiate 标头并立即重复请求,现在使用 401 HTTP标头(“好吧,先生,Web服务器!这是我的NTLM令牌。” );
  5. 服务器收到第二个请求,在 WWW-Authenticate 标头中找到NTLM令牌,对其进行验证并执行请求(“好,您可以通过。这是您的资源。” < / em>)。

最初将 Authorization: NTLM <NTLM_token> 标头设置为某个值时,情况会有所不同:

  1. 您的JS要求Authorization拥有JWT授权;
  2. 您的浏览器现在通过 Authorization HTTP标头向http://example.com/api/resource发送HTTP GET请求;
  3. Web服务器(或WebAPI本身)接收到一个请求,发现存在带有“ Bearer”身份验证方案的 http://example.com/api/resource 标头,并再次以Authorization: Bearer <JWT_token>状态码进行响应设置了 Authorization 的HTTP标头(“走开,我们不知道谁是这个'Bearer'家伙,但我们不喜欢他们。只有'NTLM'或欢迎“谈判”人!” );
  4. 浏览器收到一个401 Not Authorized响应,发现该请求已得到授权,并确定此令牌是错误的。但是,当您实际设置 WWW-Authenticate: NTLM,Negotiate 标头时,这意味着您实际上拥有凭据。因此,它会要求您在此对话框中提供此凭据。

答案 1 :(得分:0)

感谢@ vasily.sib。您是对的,我的JWTInterceptor将JWTToken添加到标题中。当我注释掉它并对其进行测试时,它起作用了。感谢堆让我免于两天的痛苦来解决问题。你是冠军。

答案 2 :(得分:0)

我也有同样的需求。我尚未在IIS(仅是Kestrel)上运行IIS,但是我设法适应了Microsoft的own instructions,以使用JWT和Windows身份验证获得每个控制器/控制器方法的身份验证。

我所做的只是从以下位置修改Startup.cs / ConfigureServices

services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
    x.RequireHttpsMetadata = false; // should be set to true in production
    x.SaveToken = true;
    x.TokenValidationParameters = generateTokenValidationParameters();
});

对此

services.AddAuthentication()
.AddNegotiate()
.AddJwtBearer(x => 
{
    x.RequireHttpsMetadata = false; // should be set to true in production
    x.SaveToken = true;
    x.TokenValidationParameters = generateTokenValidationParameters();
});

因此,基本上,删除了“默认身份验证和质询”方案,使用我先前存在的JWT配置添加了“协商(Windows Auth)”和“ JwtBearer”。

在控制器中,我通过添加此授权标头启用了Windows身份验证

[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]

类似地,我以此替换了以前执行JWD的现有Authorization标头(假设它是默认的auth / challenge方案)

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

我的应用程序将由Kestrel托管,因此IIS不会成为问题,但是无论如何,我将在下一个尝试。

@edit:我现在也已经掌握了IIS Express。通过VS的IIS Express设置(“项目属性”,“调试”选项卡)启用了Windows身份验证,然后通过将IIS添加到Startup.ConfigureServices(在AddAuthentication之后),确保IIS不对进出处理主机执行自动验证。

//disable automatic authentication for in-process hosting
services.Configure<IISServerOptions>(options => 
{
    options.AutomaticAuthentication = false;
});

//disable automatic authentication for out-of-process hosting
services.Configure<IISOptions>(options => 
{
    options.AutomaticAuthentication = false;
});

然后我将测试控制器更改为具有以下授权标头的方法

[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]

当我使用信任URL的浏览器访问该方法时,我就被允许进入User.Identity是我的Windows身份。

现在开始查看是否也可以在实际的IIS上使用。