문제

I have a WCF Service that requires a security token issued by a separate WCF STS Service. This all works just dandy. In my application, I use the service like so:

MyServiceClient myService = new MyServiceClient();
myService.Open();
myService.DoStuff();

The STS Service is called to get a token and the token is used to call the service method DoStuff.

Once the initial handshake is over, though, the myService object has the token cached and re-uses it until it expires. This is fine behavior and all, but how would I force it to refresh the token?

myService.ClientCredentials.Invalidate(); // something like this?

Such that if I called DoStuff() again it would know it needs to go to the STS again much as it did the first time.

Am I stuck just making a new proxy class object, i.e. myService = new MyServiceClient();? This works but it seems like the nuclear bomb solution.

Alternatively, is there a way to just manually get a new token and replace the current one, i.e. myService.ClientCredentials.Renew();?

If I have to make a custom ClientCredentials class to do this, how would I implement the above example methods?

도움이 되었습니까?

해결책

In my codebase, we actually cache the token so we ensure that we don't make repeated calls to the STS. Using the same method, you could definitely alter it manually request another token whenever you wish. Here's how to hook into ClientCredentials:

public class CustomClientCredentials : ClientCredentials
{
    public CustomClientCredentials()
    {
    }

    protected CustomClientCredentials(ClientCredentials other)
        : base(other)
    {
    }

    protected override ClientCredentials CloneCore()
    {
        return new CustomClientCredentials(this);
    }

    /// <summary>
    /// Returns a custom security token manager
    /// </summary>
    /// <returns></returns>
    public override  SecurityTokenManager CreateSecurityTokenManager()
    {
        return new CustomClientCredentialsSecurityTokenManager(this);
    }
}


public class CustomClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
    public CustomClientCredentialsSecurityTokenManager(ClientCredentials credentials)
        : base(credentials)
    {
    }

    /// <summary>
    /// Returns a custom token provider when a issued token is required
    /// </summary>
    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
    {
        if (IsIssuedSecurityTokenRequirement(tokenRequirement))
        {
            // Adds the endpoint behaviors for calling the issuer
            IssuedSecurityTokenProvider baseProvider = (IssuedSecurityTokenProvider)base.CreateSecurityTokenProvider(tokenRequirement);

            CustomIssuedSecurityTokenProvider provider = new CustomIssuedSecurityTokenProvider(baseProvider);
            return provider;
        }
        return base.CreateSecurityTokenProvider(tokenRequirement);
    }
}


public class CustomIssuedSecurityTokenProvider : IssuedSecurityTokenProvider
{
    private readonly IssuedSecurityTokenProvider _innerProvider;

    public CustomIssuedSecurityTokenProvider(IssuedSecurityTokenProvider innerProvider)
    {
        _innerProvider = innerProvider;
        CacheIssuedTokens = innerProvider.CacheIssuedTokens;
        IdentityVerifier = innerProvider.IdentityVerifier;
        IssuedTokenRenewalThresholdPercentage = innerProvider.IssuedTokenRenewalThresholdPercentage;
        IssuerAddress = innerProvider.IssuerAddress;
        IssuerBinding = innerProvider.IssuerBinding;
        innerProvider.IssuerChannelBehaviors.ForEach(IssuerChannelBehaviors.Add);
        KeyEntropyMode = innerProvider.KeyEntropyMode;
        MaxIssuedTokenCachingTime = innerProvider.MaxIssuedTokenCachingTime;
        MessageSecurityVersion = innerProvider.MessageSecurityVersion;
        SecurityAlgorithmSuite = innerProvider.SecurityAlgorithmSuite;
        SecurityTokenSerializer = innerProvider.SecurityTokenSerializer;
        TargetAddress = innerProvider.TargetAddress;
        innerProvider.TokenRequestParameters.ForEach(TokenRequestParameters.Add);

        _innerProvider.Open();
    }

    ~CustomIssuedSecurityTokenProvider()
    {
        _innerProvider.Close();
    }

    protected override SecurityToken GetTokenCore(TimeSpan timeout)
    {
        // We're ignoring the CacheIssuedTokens property in order to force an STS call
        var securityToken = _innerProvider.GetToken(timeout);
        return securityToken;
    }
}

The GetTokenCore() method is where the STS gets called. When you call GetToken(), the STS will be asked to issue another token.

From your question, I assume you know how to hook into your ClientCredentials from the app.config.

There might be a way of setting the CacheIssuedTokens property in the App.config file, I'm just not sure of a way off the top of my head.

다른 팁

Could you not use the IssuedToken.MaxIssuedTokenCachingTime property and set it to 0?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top