SecurityTokenHandler.ValidateToken(SecurityToken) Метод
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
При переопределении в производном классе проверяет указанный токен безопасности. Токен должен иметь тип, обрабатываемый производным классом.
public:
virtual System::Collections::ObjectModel::ReadOnlyCollection<System::Security::Claims::ClaimsIdentity ^> ^ ValidateToken(System::IdentityModel::Tokens::SecurityToken ^ token);
public virtual System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity> ValidateToken (System.IdentityModel.Tokens.SecurityToken token);
abstract member ValidateToken : System.IdentityModel.Tokens.SecurityToken -> System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity>
override this.ValidateToken : System.IdentityModel.Tokens.SecurityToken -> System.Collections.ObjectModel.ReadOnlyCollection<System.Security.Claims.ClaimsIdentity>
Public Overridable Function ValidateToken (token As SecurityToken) As ReadOnlyCollection(Of ClaimsIdentity)
Параметры
- token
- SecurityToken
Токен для проверки.
Возвращаемое значение
Идентификаторы, содержащееся в токене.
Примеры
В следующем коде показано переопределение ValidateToken метода для обработчика маркеров безопасности, который обрабатывает простые веб-маркеры (SWT). Код взят из CustomToken
примера. Сведения об этом и других примерах, доступных для WIF, а также о том, где их можно скачать, см. в разделе WiF Code Sample Index.
/// <summary>
/// This method validates the Simple Web Token.
/// </summary>
/// <param name="token">A simple web token.</param>
/// <returns>A Claims Collection which contains all the claims from the token.</returns>
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
if ( token == null )
{
throw new ArgumentNullException( "token" );
}
SimpleWebToken simpleWebToken = token as SimpleWebToken;
if ( simpleWebToken == null )
{
throw new ArgumentException("The token provided must be of type SimpleWebToken.");
}
if ( DateTime.Compare( simpleWebToken.ValidTo.Add( Configuration.MaxClockSkew ), DateTime.UtcNow ) <= 0 )
{
throw new SecurityTokenExpiredException("The incoming token has expired. Get a new access token from the Authorization Server.");
}
ValidateSignature( simpleWebToken );
ValidateAudience( simpleWebToken.Audience );
ClaimsIdentity claimsIdentity = CreateClaims( simpleWebToken );
if (this.Configuration.SaveBootstrapContext)
{
claimsIdentity.BootstrapContext = new BootstrapContext(simpleWebToken.SerializedToken);
}
List<ClaimsIdentity> claimCollection = new List<ClaimsIdentity>(new ClaimsIdentity[] { claimsIdentity });
return claimCollection.AsReadOnly();
}
В следующем коде показан CreateClaims
метод, который вызывается из переопределения ValidateToken метода в предыдущем примере. Этот метод возвращает ClaimsIdentity объект, созданный из утверждений в маркере. Код взят из CustomToken
примера. Сведения об этом и других примерах, доступных для WIF, а также о том, где их можно скачать, см. в разделе WiF Code Sample Index.
/// <summary>Creates <see cref="Claim"/>'s from the incoming token.
/// </summary>
/// <param name="simpleWebToken">The incoming <see cref="SimpleWebToken"/>.</param>
/// <returns>A <see cref="ClaimsIdentity"/> created from the token.</returns>
protected virtual ClaimsIdentity CreateClaims( SimpleWebToken simpleWebToken )
{
if ( simpleWebToken == null )
{
throw new ArgumentNullException( "simpleWebToken" );
}
NameValueCollection tokenProperties = simpleWebToken.GetAllProperties();
if ( tokenProperties == null )
{
throw new SecurityTokenValidationException( "No claims can be created from this Simple Web Token." );
}
if ( Configuration.IssuerNameRegistry == null )
{
throw new InvalidOperationException( "The Configuration.IssuerNameRegistry property of this SecurityTokenHandler is set to null. Tokens cannot be validated in this state." );
}
string normalizedIssuer = Configuration.IssuerNameRegistry.GetIssuerName( simpleWebToken );
ClaimsIdentity identity = new ClaimsIdentity(AuthenticationTypes.Federation);
foreach ( string key in tokenProperties.Keys )
{
if ( ! IsReservedKeyName(key) && !string.IsNullOrEmpty( tokenProperties[key] ) )
{
identity.AddClaim( new Claim( key, tokenProperties[key], ClaimValueTypes.String, normalizedIssuer ) );
if ( key == AcsNameClaimType )
{
// add a default name claim from the Name identifier claim.
identity.AddClaim( new Claim( DefaultNameClaimType, tokenProperties[key], ClaimValueTypes.String, normalizedIssuer ) );
}
}
}
return identity;
}
В следующем коде показан ValidateSignature
метод, который вызывается из переопределения ValidateToken метода в простом обработчике веб-маркера. Этот метод проверяет подпись маркера с помощью настроенного IssuerTokenResolver. Код взят из CustomToken
примера. Сведения об этом и других примерах, доступных для WIF, а также о том, где их можно скачать, см. в разделе WiF Code Sample Index.
/// <summary>
/// Validates the signature on the incoming token.
/// </summary>
/// <param name="simpleWebToken">The incoming <see cref="SimpleWebToken"/>.</param>
protected virtual void ValidateSignature( SimpleWebToken simpleWebToken )
{
if ( simpleWebToken == null )
{
throw new ArgumentNullException( "simpleWebToken" );
}
if ( String.IsNullOrEmpty( simpleWebToken.SerializedToken ) || String.IsNullOrEmpty( simpleWebToken.Signature ) )
{
throw new SecurityTokenValidationException( "The token does not have a signature to verify" );
}
string serializedToken = simpleWebToken.SerializedToken;
string unsignedToken = null;
// Find the last parameter. The signature must be last per SWT specification.
int lastSeparator = serializedToken.LastIndexOf( ParameterSeparator );
// Check whether the last parameter is an hmac.
if ( lastSeparator > 0 )
{
string lastParamStart = ParameterSeparator + SimpleWebTokenConstants.Signature + "=";
string lastParam = serializedToken.Substring( lastSeparator );
// Strip the trailing hmac to obtain the original unsigned string for later hmac verification.
if ( lastParam.StartsWith( lastParamStart, StringComparison.Ordinal ) )
{
unsignedToken = serializedToken.Substring( 0, lastSeparator );
}
}
SimpleWebTokenKeyIdentifierClause clause = new SimpleWebTokenKeyIdentifierClause(simpleWebToken.Audience);
InMemorySymmetricSecurityKey securityKey = null;
try
{
securityKey = (InMemorySymmetricSecurityKey)this.Configuration.IssuerTokenResolver.ResolveSecurityKey(clause);
}
catch (InvalidOperationException)
{
throw new SecurityTokenValidationException( "A Symmetric key was not found for the given key identifier clause.");
}
string generatedSignature = GenerateSignature( unsignedToken, securityKey.GetSymmetricKey() );
if ( string.CompareOrdinal( generatedSignature, simpleWebToken.Signature ) != 0 )
{
throw new SecurityTokenValidationException( "The signature on the incoming token is invalid.") ;
}
}
/// <summary>
/// Generates an HMACSHA256 signature for a given string and key.
/// </summary>
/// <param name="unsignedToken">The token to be signed.</param>
/// <param name="signingKey">The key used to generate the signature.</param>
/// <returns>The generated signature.</returns>
protected static string GenerateSignature(string unsignedToken, byte[] signingKey)
{
using (HMACSHA256 hmac = new HMACSHA256(signingKey))
{
byte[] signatureBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken));
string signature = HttpUtility.UrlEncode(Convert.ToBase64String(signatureBytes));
return signature;
}
}
В следующем коде показан ValidateAudience
метод, который вызывается из переопределения ValidateToken метода в простом обработчике веб-маркера. Этот метод проверяет аудиторию, содержащуюся в маркере, по URI аудитории, указанной в конфигурации. Код взят из CustomToken
примера. Сведения об этом и других примерах, доступных для WIF, а также о том, где их можно скачать, см. в разделе WiF Code Sample Index.
/// <summary>
/// Validates the audience of the incoming token with those specified in configuration.
/// </summary>
/// <param name="tokenAudience">The audience of the incoming token.</param>
protected virtual void ValidateAudience( string tokenAudience )
{
if ( Configuration.AudienceRestriction.AudienceMode != AudienceUriMode.Never )
{
if ( String.IsNullOrEmpty( tokenAudience ) )
{
throw new SecurityTokenValidationException("The incoming token does not have a valid audience Uri and the Audience Restriction is not set to 'None'.");
}
if ( Configuration.AudienceRestriction.AllowedAudienceUris.Count == 0 )
{
throw new InvalidOperationException( " Audience Restriction is not set to 'None' but no valid audience URI's are configured." );
}
IList<Uri> allowedAudienceUris = Configuration.AudienceRestriction.AllowedAudienceUris;
Uri audienceUri = null;
Uri.TryCreate(tokenAudience, UriKind.RelativeOrAbsolute, out audienceUri);
// Strip off any query string or fragment.
Uri audienceLeftPart;
if ( audienceUri.IsAbsoluteUri )
{
audienceLeftPart = new Uri( audienceUri.GetLeftPart( UriPartial.Path ) );
}
else
{
Uri baseUri = new Uri( "http://www.example.com" );
Uri resolved = new Uri( baseUri, tokenAudience );
audienceLeftPart = baseUri.MakeRelativeUri( new Uri( resolved.GetLeftPart( UriPartial.Path ) ) );
}
if ( !allowedAudienceUris.Contains( audienceLeftPart ) )
{
throw new AudienceUriValidationFailedException(
"The Audience Uri of the incoming token is not present in the list of permitted Audience Uri's.");
}
}
}
Комментарии
По умолчанию этот метод создает NotImplementedException исключение.
Метод ValidateToken вызывается инфраструктурой для проверки и извлечения утверждений из десериализованного маркера безопасности. Эти утверждения возвращаются в коллекции объектов, ClaimsIdentity возвращаемых методом . В типичном случае эта коллекция будет содержать одно удостоверение.
В производных классах проверка обычно включает проверку целевой аудитории, указанной в токене, по URI аудитории, указанной в SecurityTokenHandlerConfiguration.AudienceRestriction свойстве объекта конфигурации обработчика маркеров, указанного в свойстве Configuration . Эти URI обычно задаются в файле конфигурации в элементе <audienceUris> . Если аудитория не может быть проверена, AudienceUriValidationFailedException должно быть вызвано исключение.
При обработке маркера издатель обычно проверяется путем передачи маркера издателя в один из GetIssuerName методов IssuerNameRegistry объекта, настроенного для обработчика с помощью Configuration свойства . Реестр имен издателя обычно настраивается с помощью <элемента issuerNameRegistry> в файле конфигурации. Возвращает GetIssuerName имя издателя. Это имя следует использовать для задания Claim.Issuer свойства в утверждениях, содержащихся в маркере. Если реестр имен издателя не содержит запись для токена издателя, GetIssuerName возвращает .null
В этом случае SecurityTokenException обычно создается в производных классах, но это поведение определяется конструктором класса .