(TL; DR: проверить последнее обновление)
Первая проблема заключается в том, что API изменился между различными версиями ядра .net.
Второй: каждый пример, который я нахожу в Интернете, немного отличается от нереального авторитетного ответа о том, что и для чего; Скорее, я продолжаю находить посты с надписью «О, это сработало для меня», но похоже, что все, как и я, экспериментируют с этим, а не имеют полное понимание.
Во всяком случае, вот код:
Services.AddAuthentication(A =>
{
A.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
A.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(O =>
{
O.RequireHttpsMetadata = false;
O.SaveToken = true;
O.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthJWTPublicKey)),
ValidateIssuer = false,
ValidateAudience = false
};
});
У меня есть допустимый JWT, но любой вызов моего контроллера приводит к немедленной ошибке 401.
Я попытался украсить контроллер:
[Авторизоваться]
[Authorize (Roles = "offline_access")]
[Authorize (AuthenticationSchemes =
JwtBearerDefaults.AuthenticationScheme, Roles = "offline_access")]
но не повезло
Содержимое JWT:
{
"jti":"837c2dd1-cca5-491e-84a4-b17429366df5",
"exp":1558355152,
"nbf":0,
"iat":1558354852,
"iss":"xxxx",
"aud":"account",
"sub":"4ed1c313-c692-44db-86d3-7605f3e2c2c1",
"typ":"Bearer",
"azp":"test-app",
"auth_time":1558354850,
"session_state":"e40c9a95-ae8a-4d6e-b2a4-ad5e833867ea",
"acr":"1",
"realm_access":{
"roles":[
"offline_access",
"uma_authorization"
]
},
"resource_access":{
"account":{
"roles":[
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope":"openid email profile",
"email_verified":true,
"name":"firstd6d05 last29954",
"preferred_username":"xxxx",
"given_name":"firstd6d05",
"family_name":"last29954",
"email":"xxxx",
"group":[
"/Administrators"
]
}
Моя цель - просто проверить подпись JWT (и, в конечном итоге, срок ее действия) и получить доступ к токену в контроллере.
Я передаю JWT через заголовок в разделе «Авторизация» и с текстом «Несущий» перед токеном.
Чего мне не хватает?
Следуя ответу ниже, я сделал следующее изменение:
Я добавил:
Services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
, а затем добавил следующий класс с перерывом
internal class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
Debugger.Break();
}
}
но я все еще получаю 401 с токеном Keycloak; так что похоже, что он не доходит до преобразователя утверждений, пока не будет отклонен.
Я добавил отладочный вывод ASP.
Это по адресу: https://pastebin.com/qvGsQG6j
Соответствующая часть выглядит так:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
Authorization failed.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Info:Authorization failed.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Info:Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Info:Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Info:Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
Эта конкретная строка может объяснить проблему:
Ошибка авторизации для запроса в фильтре 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'
но «провал» кажется мне немного расплывчатым.
Последний тест:
У меня есть этот токен:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoibXkgbmFtZSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6Im5vQGVtYWlsLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvZXhwaXJhdGlvbiI6IjA1LzMxLzIwMTkgMDA6MTM6MjAiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9zaWQiOiI3Y2FjZjdiNS04NjY5LTQ2OWUtOTg4NS1kNDgwNGYyOGNjNGEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcy9hY3RvciI6ImQyZjZiNzI0LWE0ZjktNGJkZC1hNjQ3LTRkM2UxYTU5NjhkZSIsIm5iZiI6MTU1OTE3NTIwMCwiZXhwIjoxNTU5MjYxNjAwLCJpc3MiOiJ0ZXN0IiwiYXVkIjoidGVzdC1hcHAifQ.y42RUvMM69aDTvCydoU3mOKu2giub6OvKpd-RNVmom4
с ключом:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjayVuqZOuKK38rhsRwrRGzVcv/7b4fHXrzpol3K5TTAPttNUaQvCKQD7BQN+V8nvkBsQcxPk5ONnxzbFb/npENC4UtwK5J6iiVrinE7sDrWZQNo9LkwbuG9x0fuuf8U3H2CnwZEfFaf2kbU1v7XosNGi+aYASupvhwoiJtK+17ZPloxSQy3Qny2tQWi7Dh/Cr5+m5JBy6HeGLq2cq+oalFYzrGGmQXndLtJpBZgrPd7nR6lJSMiRcJtcpxTJbYTEVVXoB0SR1bPmYYB/6y7klVDVedTow+1mwZrDMrbRiTBPSifCIBs3rxLQaL207blg+kj+EVLED5fZSOBlOyTOYQIDAQAB
он декодирует (проверено jwt.io):
{
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "my name",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "no@email.com",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration": "05/31/2019 00:13:20",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid": "7cacf7b5-8669-469e-9885-d4804f28cc4a",
"http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor": "d2f6b724-a4f9-4bdd-a647-4d3e1a5968de",
"nbf": 1559175200,
"exp": 1559261600,
"iss": "test",
"aud": "test-app"
}
генерируется следующим кодом:
var Expiration = DateTime.UtcNow + TimeSpan.FromDays(1);
var Identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "my name"),
new Claim(ClaimTypes.Email, "no@email.com"),
new Claim(ClaimTypes.Expiration, Expiration.ToString(CultureInfo.InvariantCulture)),
new Claim(ClaimTypes.Sid, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Actor, Guid.NewGuid().ToString()),
});
var Token = new JwtSecurityToken
(
issuer: "test",
audience: "test-app",
claims: Identity.Claims,
notBefore: DateTime.UtcNow,
expires: Expiration,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_JwtRsaPublicKey)), SecurityAlgorithms.HmacSha256)
);
var TokenString = new JwtSecurityTokenHandler().WriteToken(Token);
return TokenString;
В asp у меня есть следующий код:
Services.AddAuthentication(A =>
{
A.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
A.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(O =>
{
O.RequireHttpsMetadata = false;
O.SaveToken = true;
O.IncludeErrorDetails = true;
O.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthJWTPublicKey)),
ValidateIssuer = false,
ValidateAudience = false
};
});
и у меня есть метод контроллера с:
[Authorize]
Но я продолжаю получать 401, независимо от того, что я пытаюсь, я получаю 401 ...
Даже если я установлю ValidateIssuerSigningKey в false. Я получаю 401
Настройка:
В ConfigureServices у меня есть:
Services.AddMvc()
and the code above
В Configure у меня есть:
Application.UseAuthentication();
Application.UseMvc(Routes => { Routes.MapRoute("default_route", "{controller}/{action}/{id?}"); });