如上图所示,可以正确的返回access_token,且有标记的过期时间。
2、如何校验token的有效性?
IdentityServer4给已经提供了Token的校验地址http://xxxxxx/connect/introspect,可以通过访问此地址来校验Token的有效性,使用前需要了解传输的参数和校验方式。
在授权篇开始时我介绍了IdentityServer4的源码剖析,相信都掌握了看源码的方式,这里就不详细介绍了。
核心代码为IntrospectionEndpoint,标注出校验的核心代码,用到的几个校验方式已经注释出来了。
private async Task<IEndpointResult> ProcessIntrospectionRequestAsync(HttpContext context) { _logger.LogDebug("Starting introspection request."); // 校验ApiResources信息,支持 basic 和 form两种方式,和授权时一样 var apiResult = await _apiSecretValidator.ValidateAsync(context); if (apiResult.Resource == null) { _logger.LogError("API unauthorized to call introspection endpoint. aborting."); return new StatusCodeResult(HttpStatusCode.Unauthorized); } var body = await context.Request.ReadFormAsync(); if (body == null) { _logger.LogError("Malformed request body. aborting."); await _events.RaiseAsync(new TokenIntrospectionFailureEvent(apiResult.Resource.Name, "Malformed request body")); return new StatusCodeResult(HttpStatusCode.BadRequest); } // 验证access_token的有效性,根据 _logger.LogTrace("Calling into introspection request validator: {type}", _requestValidator.GetType().FullName); var validationResult = await _requestValidator.ValidateAsync(body.AsNameValueCollection(), apiResult.Resource); if (validationResult.IsError) { LogFailure(validationResult.Error, apiResult.Resource.Name); await _events.RaiseAsync(new TokenIntrospectionFailureEvent(apiResult.Resource.Name, validationResult.Error)); return new BadRequestResult(validationResult.Error); } // response generation _logger.LogTrace("Calling into introspection response generator: {type}", _responseGenerator.GetType().FullName); var response = await _responseGenerator.ProcessAsync(validationResult); // render result LogSuccess(validationResult.IsActive, validationResult.Api.Name); return new IntrospectionResult(response); } //校验Token有效性核心代码 public async Task<TokenValidationResult> ValidateAccessTokenAsync(string token, string expectedScope = null) { _logger.LogTrace("Start access token validation"); _log.ExpectedScope = expectedScope; _log.ValidateLifetime = true; TokenValidationResult result; if (token.Contains(".")) {//jwt if (token.Length > _options.InputLengthRestrictions.Jwt) { _logger.LogError("JWT too long"); return new TokenValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken, ErrorDescription = "Token too long" }; } _log.AccessTokenType = AccessTokenType.Jwt.ToString(); result = await ValidateJwtAsync( token, string.Format(Constants.AccessTokenAudience, _context.HttpContext.GetIdentityServerIssuerUri().EnsureTrailingSlash()), await _keys.GetValidationKeysAsync()); } else {//Reference token if (token.Length > _options.InputLengthRestrictions.TokenHandle) { _logger.LogError("token handle too long"); return new TokenValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken, ErrorDescription = "Token too long" }; } _log.AccessTokenType = AccessTokenType.Reference.ToString(); result = await ValidateReferenceAccessTokenAsync(token); } _log.Claims = result.Claims.ToClaimsDictionary(); if (result.IsError) { return result; } // make sure client is still active (if client_id claim is present)
