How can I enforce Windows Authentication on some controllers and Bearer Authentication on others?
Firstly, I have to say it is somehow weird when dealing with the mixed schemes of JWT and Windows Authentication. I mean when an user who is not authenticated by JwtBearer, tries to access those url resources protected by JwtBearer Scheme, will be challenged by Windows authentication.
Secondly, as for your question, we can configure the JwtBearer authentication to use a custom token which is not used as the HTTP header (i.e. Authorization: Bearer xxxx_yyyy_zzz) . For example, send the JWT token by querystring or a custom header.
How to In Details :
Configure the JwtBearer authentication to read token from querystring:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options=> {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
options.Events = new JwtBearerEvents() {
OnMessageReceived = async (context) =>{
var bearer=context.HttpContext.Request.Query["bearer"].FirstOrDefault();
if(!String.IsNullOrEmpty(bearer)){
context.Token = bearer;
}
},
};
});
For a testing purpose, I add a dummy policy handler for your MyPolicy:
services.AddAuthorization(o => {
o.AddPolicy("MyPolicy",p => {
p.Requirements.Add(new MyPolicyRequirement());
});
});
services.AddSingleton<IAuthorizationHandler,MyPolicyRequirementHandler>();
services.AddHttpContextAccessor();
Here the MyPolicyRequirementHandler is :
public class MyPolicyRequirementHandler : AuthorizationHandler<MyPolicyRequirement>
{
public MyPolicyRequirementHandler()
{
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyPolicyRequirement requirement)
{
var user= context.User;
if (user.Identity.IsAuthenticated)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
And the two controllers protected by the Authentication of Windows or JwtBearer :
[Authorize(AuthenticationSchemes = "Windows")]
[Route("api/[controller]")]
[ApiController]
public class PingController : ControllerBase
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "Pong" };
}
}
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy ="MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class FooController : ControllerBase
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "Bar" };
}
}
Test Case :
Test with Windows Authentication
A Screenshot when accessing the /api/ping

Test with Jwt Bearer Authentication
Firstly, generate a JwtToken on server side :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s
And then send a HTTP GET request to the endpoint of /api/foo with a querystring of bearer=xxx_yyy_zzz :
GET https://localhost:44385/api/foo?bearer=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s HTTP/1.1
it will return [foo] as expected :
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTZcV2luZG93c0F1dGh0ZW50aWNhdGlvbkFuZEp3dEF1dGhlbnRpY2F0aW9uXEFwcFxhcGlcZm9v?=
X-Powered-By: ASP.NET
["Bar"]