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":
- 您在浏览器中导航至
http://example.com/api/resource
;
- 您的浏览器向
http://example.com/api/resource
发送 HTTP GET 请求,目前没有任何 Authorization
HTTP Header(匿名请求);
- 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!");
- 浏览器收到
401
响应,发现请求是匿名的,查看 WWW-Authenticate
header 并立即重复请求,现在使用 Authorization: NTLM <NTLM_token>
HTTP Header ("Ok, take it easy, mr. Web server! Here is my NTLM token.");
- 服务器收到第二个请求,在
Authorization
header中找到NTLM令牌,验证并执行请求("Ok, you may pass. Here is your resource.").
事情有点不同,当您最初将 Authorization
header 设置为某个值时:
- 您的 JS 需要
http://example.com/api/resource
JWT 授权;
- 您的浏览器现在使用
Authorization: Bearer <JWT_token>
HTTP Header 向 http://example.com/api/resource
发送 HTTP GET 请求;
- 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!");
- 浏览器收到
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。
我 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":
- 您在浏览器中导航至
http://example.com/api/resource
; - 您的浏览器向
http://example.com/api/resource
发送 HTTP GET 请求,目前没有任何Authorization
HTTP Header(匿名请求); - 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!"); - 浏览器收到
401
响应,发现请求是匿名的,查看WWW-Authenticate
header 并立即重复请求,现在使用Authorization: NTLM <NTLM_token>
HTTP Header ("Ok, take it easy, mr. Web server! Here is my NTLM token."); - 服务器收到第二个请求,在
Authorization
header中找到NTLM令牌,验证并执行请求("Ok, you may pass. Here is your resource.").
事情有点不同,当您最初将 Authorization
header 设置为某个值时:
- 您的 JS 需要
http://example.com/api/resource
JWT 授权; - 您的浏览器现在使用
Authorization: Bearer <JWT_token>
HTTP Header 向http://example.com/api/resource
发送 HTTP GET 请求; - 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!"); - 浏览器收到
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。