Как обеспечить проверку подлинности Windows на некоторых контроллерах и проверку подлинности на носителе на других?
Во-первых, я должен сказать, что это как-то странно при работе со смешанными схемами JWT и Windows Authentication. Я имею в виду, когда пользователь, который не аутентифицирован JwtBearer
, пытается получить доступ к ресурсам URL, защищенным схемой JwtBearer
, будет подвергнут сомнению аутентификацией Windows.
Во-вторых, что касается вашего вопроса, мы можем настроить аутентификацию JwtBearer
на использование пользовательского токена, который не используется в качестве заголовка HTTP
(т.е. Authorization: Bearer xxxx_yyyy_zzz
) . Например, отправьте токен JWT
по строке запроса или пользовательскому заголовку.
Как в деталях:
Настройка JwtBearer
аутентификации для чтения токена из строки запроса:
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;
}
},
};
});
Для целей тестирования я добавляю фиктивный обработчик политики для вашего MyPolicy
:
services.AddAuthorization(o => {
o.AddPolicy("MyPolicy",p => {
p.Requirements.Add(new MyPolicyRequirement());
});
});
services.AddSingleton<IAuthorizationHandler,MyPolicyRequirementHandler>();
services.AddHttpContextAccessor();
Здесь MyPolicyRequirementHandler
:
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;
}
}
И два контроллера защищены Аутентификацией Windows
или 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" };
}
}
Контрольный пример:
Тест с аутентификацией Windows
Снимок экрана при доступе к /api/ping
Тест с аутентификацией на носителе Jwt
Во-первых, сгенерируйте JwtToken
на стороне сервера:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s
А затем отправьте HTTP-запрос GET в конечную точку /api/foo
со строкой запроса bearer=xxx_yyy_zzz
:
GET https://localhost:44385/api/foo?bearer=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6Iml0bWludXMiLCJuYmYiOjE1NDIzNDMxNzMsImV4cCI6MTU0MjQxNTE3MywiaWF0IjoxNTQyMzQzMTczLCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM4NSIsImF1ZCI6IndlYmNsaWVudCJ9.iMnq8UBRQforNeRBehrULAScD8D2-ta4nmdQt1rTZ3s HTTP/1.1
вернет [foo]
как и ожидалось:
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"]