#asp.net-core #oauth-2.0 #openid-connect #openid
Вопрос:
Я использую поток с Openid, где я перенаправляю своего пользователя к другому поставщику, чтобы позаботиться о входе в систему, и после этого входа я получаю code
URL-адрес в моем /логине/обратном вызове?код=xxxx.
Итак, JWT генерируется с использованием code
, но я не могу его проверить. У меня нет well-known
конечной точки в моей STS, мне нужно настроить ее вручную таким образом:
services.AddAuthorization(cfg =>
{
cfg.AddPolicy("MyPolicy", cfgPolicy =>
{
cfgPolicy.AddRequirements().RequireAuthenticatedUser();
cfgPolicy.AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme);
});
}).AddAuthentication(cfg =>
{
cfg.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
cfg.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(cfg =>
{
cfg.ClientId = authenticationConfig.ClientId;
cfg.ClientSecret = authenticationConfig.ClientSecret;
cfg.ResponseType = "code";
cfg.CallbackPath = "/login/callback";
cfg.Scope.Clear();
cfg.Scope.Add("openid");
cfg.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "https://myissuer"
};
cfg.Configuration = new OpenIdConnectConfiguration
{
AuthorizationEndpoint = "https://mysts/api/oauth/authorize",
TokenEndpoint = "https://mysts/api/oauth/token",
UserInfoEndpoint = "https://mysts/api/oauth/token_info"
};
});
Некоторые важные моменты:
- У меня есть конечная точка опроса токена для проверки моего токена (конечная точка token_info).
- У меня нет конечной точки по умолчанию для возврата открытых ключей (jwks). Моя конечная точка всегда связана с некоторыми значениями, что-то в этом роде … > https://mysts/offline/jwks/{kid}/{clientid}, так что это динамично и зависит от токена.
- У меня нет хорошо известной конечной точки.
Комментарии:
1. Не могли бы вы, пожалуйста, сказать мне, в чем ваш вопрос? Вы хотите, чтобы мы помогли вам в чем ?
2. «у меня есть конечная точка самоанализа токенов», вы также можете отправить каждый токен в конечную точку самоанализа для проверки, и это, вероятно, будет проще реализовать, но в конечном итоге будет медленнее с точки зрения выполнения (учитывая, что это синхронизация по асинхронности и все такое).
Ответ №1:
Вы не можете подтвердить это, потому что, ASP.NET Ядро пытается проверить подпись JWT по умолчанию. Однако, поскольку вы сами настроили метаданные, а не дали a JwksUri
, у него нет возможности получить открытый ключ поставщика OIDC для проверки подписи.
Вы можете указать JwksUri
или отключить проверку подписи (НЕБЕЗОПАСНО), или проверить ее самостоятельно. Если у вас есть доступ к открытому ключу, каким-то образом используйте options.SecurityTokenValidator
и реализуйте a ISecurityTokenValidator
для пользовательской проверки.
Вот (не проверенная) реализация, которая динамически извлекает JWKS и проверяет токен:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddOpenIdConnect(options => {
options.SecurityTokenValidator = new MyJwtValidator(Configuration);
});
}
class MyJwtValidator: ISecurityTokenValidator
{
private readonly IConfiguration _configuration;
private readonly HttpClient _httpClient;
private readonly JwtSecurityTokenHandler _tokenHandler;
public MyJwtValidator(IConfiguration configuration)
{
_configuration = configuration;
_tokenHandler = new JwtSecurityTokenHandler();
_httpClient = new HttpClient
{
BaseAddress = new Uri(_configuration.GetSection("OidcProvider").Get<string>())
};
}
public bool CanReadToken(string securityToken) => true;
public ClaimsPrincipal ValidateToken(
string securityToken,
TokenValidationParameters validationParameters,
out SecurityToken validatedToken
)
{
// parse the token (without validating) to extract a value
var parsedToken = new JwtSecurityToken(securityToken);
var keyId = parsedToken.Claims.First(c => c.Type == "kid").Value;
// fetch JWKS and validate the token
var clientId = _configuration.GetSection("OidcProvider:ClientId").Get<string>();
var jwks = _httpClient.GetStringAsync($"url/to/jwks/{keyId}/{clientId}").Resu<
// jwks == "{ keys: [..."
var signingKeys = new JsonWebKeySet(jwks).GetSigningKeys();
return _tokenHandler.ValidateToken(securityToken, new TokenValidationParameters
{
IssuerSigningKeys = signingKeys
}, out validatedToken);
}
public bool CanValidateToken { get; } = true;
public int MaximumTokenSizeInBytes { get; set; } = int.MaxValue;
}
Он выполняет синхронизацию по асинхронности, что не одобряется, но вы можете кэшировать ключи, чтобы избежать уплаты штрафа.
Комментарии:
1. Спасибо, я буду использовать это решение, чтобы сделать свой собственный токен проверки.