查看源码:https://github.com/IdentityServer/IdentityServer4/tree/release
API使用Client Credentials的token验证是使用jwt验证的
找到JwtBearerClientAssertionSecretParser 类
public async Task<ParsedSecret> ParseAsync(HttpContext context) { _logger.LogDebug("Start parsing for JWT client assertion in post body"); if (!context.Request.HasFormContentType) { _logger.LogDebug("Content type is not a form"); return null; } var body = await context.Request.ReadFormAsync(); if (body != null) { var clientAssertionType = body[OidcConstants.TokenRequest.ClientAssertionType].FirstOrDefault(); var clientAssertion = body[OidcConstants.TokenRequest.ClientAssertion].FirstOrDefault(); if (clientAssertion.IsPresent() && clientAssertionType == OidcConstants.ClientAssertionTypes.JwtBearer) { if (clientAssertion.Length > _options.InputLengthRestrictions.Jwt) { _logger.LogError("Client assertion token exceeds maximum lenght."); return null; } var clientId = GetClientIdFromToken(clientAssertion); if (!clientId.IsPresent()) { return null; } if (clientId.Length > _options.InputLengthRestrictions.ClientId) { _logger.LogError("Client ID exceeds maximum lenght."); return null; } var parsedSecret = new ParsedSecret { Id = clientId, Credential = clientAssertion, Type = IdentityServerConstants.ParsedSecretTypes.JwtBearer }; return parsedSecret; } } _logger.LogDebug("No JWT client assertion found in post body"); return null; }
首先从Context中拿到token信息
然后从中解析出ClientId
private string GetClientIdFromToken(string token) { try { var jwt = new JwtSecurityToken(token); return jwt.Subject; } catch (Exception e) { _logger.LogWarning("Could not parse client assertion", e); return null; } }
获取到ClientId后进行判断
public async Task<ClientSecretValidationResult> ValidateAsync(HttpContext context) { _logger.LogDebug("Start client validation"); var fail = new ClientSecretValidationResult { IsError = true }; var parsedSecret = await _parser.ParseAsync(context); if (parsedSecret == null) { await RaiseFailureEventAsync("unknown", "No client id found"); _logger.LogError("No client identifier found"); return fail; } // load client var client = await _clients.FindEnabledClientByIdAsync(parsedSecret.Id); if (client == null) { await RaiseFailureEventAsync(parsedSecret.Id, "Unknown client"); _logger.LogError("No client with id '{clientId}' found. aborting", parsedSecret.Id); return fail; } if (!client.RequireClientSecret || client.IsImplicitOnly()) { _logger.LogDebug("Public Client - skipping secret validation success"); } else { var result = await _validator.ValidateAsync(parsedSecret, client.ClientSecrets); if (result.Success == false) { await RaiseFailureEventAsync(client.ClientId, "Invalid client secret"); _logger.LogError("Client secret validation failed for client: {clientId}.", client.ClientId); return fail; } } _logger.LogDebug("Client validation success"); var success = new ClientSecretValidationResult { IsError = false, Client = client, Secret = parsedSecret }; await RaiseSuccessEventAsync(client.ClientId, parsedSecret.Type); return success; }
验证
public async Task<SecretValidationResult> ValidateAsync(ParsedSecret parsedSecret, IEnumerable<Secret> secrets) { var secretsArray = secrets as Secret[] ?? secrets.ToArray(); var expiredSecrets = secretsArray.Where(s => s.Expiration.HasExpired(_clock.UtcNow.UtcDateTime)).ToList(); if (expiredSecrets.Any()) { expiredSecrets.ForEach( ex => _logger.LogWarning("Secret [{description}] is expired", ex.Description ?? "no description")); } var currentSecrets = secretsArray.Where(s => !s.Expiration.HasExpired(_clock.UtcNow.UtcDateTime)).ToArray(); // see if a registered validator can validate the secret foreach (var validator in _validators) { var secretValidationResult = await validator.ValidateAsync(currentSecrets, parsedSecret); if (secretValidationResult.Success) { _logger.LogDebug("Secret validator success: {0}", validator.GetType().Name); return secretValidationResult; } } _logger.LogDebug("Secret validators could not validate secret"); return new SecretValidationResult { Success = false }; }
在Web API项目中可以直接从Request中拿到token
var bearer = (((Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.FrameRequestHeaders)Request.Headers).HeaderAuthorization); var token = bearer.ToString().Replace("Bearer ", ""); JwtSecurityToken jwt = new JwtSecurityToken(token); var clientId = jwt.Claims.FirstOrDefault(x => x.Type == "client_id").Value;