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

ASP.Net Core 2.0 mixed authentication of JWT and Windows Authentication doesn't accept credentials

我 API 在 asp.net 核心 2.0 中创建,我在其中使用混合模式身份验证。对于一些控制器 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 问题吗?

谢谢

您需要确保在尝试使用 Windows Auth 时 NOT 设置 Authorization: Bearer <JWT_token> HTTP header。这里的关键点是 "Windows Auth" 是如何工作的。让我们看看它如何与浏览器一起工作。

我们称它为 "a normal flow":

  1. 您在浏览器中导航至 http://example.com/api/resource
  2. 您的浏览器向 http://example.com/api/resource 发送 HTTP GET 请求,目前没有任何 Authorization HTTP Header(匿名请求);
  3. Web 服务器(或 WebAPI 本身)收到请求,发现没有 Authorization header 并响应 401 Not Authorized 设置 WWW-Authenticate: NTLM,Negotiate HTTP Header 的状态代码 ("Go away, no anonymous access. Only 'NTLM' or 'Negotiate' guys are welcome!");
  4. 浏览器收到 401 响应,发现请求是匿名的,查看 WWW-Authenticate header 并立即重复请求,现在使用 Authorization: NTLM <NTLM_token> HTTP Header ("Ok, take it easy, mr. Web server! Here is my NTLM token.");
  5. 服务器收到第二个请求,在Authorizationheader中找到NTLM令牌,验证并执行请求("Ok, you may pass. Here is your resource.").

事情有点不同,当您最初将 Authorization header 设置为某个值时:

  1. 您的 JS 需要 http://example.com/api/resource JWT 授权;
  2. 您的浏览器现在使用 Authorization: Bearer <JWT_token> HTTP Header 向 http://example.com/api/resource 发送 HTTP GET 请求;
  3. Web 服务器(或 WebAPI 本身)收到请求,发现有 Authorization header 和 "Bearer" 身份验证方案并再次响应 401 Not Authorized 状态代码并设置 WWW-Authenticate: NTLM,Negotiate HTTP Header ("Go away, we don't know who are this 'Bearer' guys, but we don't like them. Only 'NTLM' or 'Negotiate' guys are welcome!");
  4. 浏览器收到 401 响应,发现请求 已被 授权并确定此令牌是错误的。但是,当您实际设置 Authorization header 时,这意味着您实际上 拥有 一些凭据。因此它会通过此对话框要求您提供此凭据。

我也有同样的需求。我还没有 运行 IIS 上的东西,只有 Kestrel,但我设法调整了 Microsoft 的 own instructions 以使用 JWT 和 Windows auth 获得每个 controller/controller 方法身份验证。

我所做的只是修改 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();
});

所以,基本上,删除了默认身份验证和质询方案,使用我的 pre-existing JWT 配置添加了协商(Windows Auth)和 JwtBearer。

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

[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]

同样,我用这个

替换了之前执行 JWD 的现有授权 header(假定它是默认的 auth/challenge 方案)
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

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

@edit:我现在也掌握了 IIS Express。通过 VS 的 IIS Express 设置(项目属性,调试选项卡)启用 Windows 身份验证,然后通过将此添加到 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;
});

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

[Authorize(AuthenticationSchemes = IISDefaults.AuthenticationScheme)]

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

现在看看它是否也适用于实际的 IIS。