Delen via


Aangepast token

In dit voorbeeld ziet u hoe u een aangepaste token-implementatie toevoegt aan een WCF-toepassing (Windows Communication Foundation). In het voorbeeld wordt een CreditCardToken functie gebruikt om veilig informatie over clientcreditcards door te geven aan de service. Het token wordt doorgegeven in de berichtkop WS-Security en wordt ondertekend en versleuteld met behulp van het symmetrische beveiligingsbindingselement, samen met de berichttekst en andere berichtkoppen. Dit is handig in gevallen waarin de ingebouwde tokens niet voldoende zijn. In dit voorbeeld ziet u hoe u een aangepast beveiligingstoken aan een service kunt bieden in plaats van een van de ingebouwde tokens te gebruiken. De service implementeert een contract dat een communicatiepatroon aanvraagantwoord definieert.

Notitie

De installatieprocedure en build-instructies voor dit voorbeeld bevinden zich aan het einde van dit onderwerp.

Samenvattend ziet u in dit voorbeeld het volgende:

  • Hoe een client een aangepast beveiligingstoken aan een service kan doorgeven.

  • Hoe de service een aangepast beveiligingstoken kan gebruiken en valideren.

  • Hoe de WCF-servicecode de informatie over ontvangen beveiligingstokens kan verkrijgen, inclusief het aangepaste beveiligingstoken.

  • Hoe het X.509-certificaat van de server wordt gebruikt om de symmetrische sleutel te beveiligen die wordt gebruikt voor berichtversleuteling en handtekening.

Clientverificatie met behulp van een aangepast beveiligingstoken

De service maakt één eindpunt beschikbaar dat programmatisch wordt gemaakt met behulp van BindingHelper en EchoServiceHost klassen. Het eindpunt bestaat uit een adres, een binding en een contract. De binding wordt geconfigureerd met een aangepaste binding met behulp van SymmetricSecurityBindingElement en HttpTransportBindingElement. In dit voorbeeld wordt het SymmetricSecurityBindingElement X.509-certificaat van een service ingesteld om de symmetrische sleutel tijdens de verzending te beveiligen en om een aangepaste CreditCardToken berichtheader in een WS-Security-berichtkop door te geven als een ondertekend en versleuteld beveiligingstoken. Het gedrag geeft de servicereferenties op die moeten worden gebruikt voor clientverificatie en ook informatie over het X.509-certificaat van de service.

public static class BindingHelper
{
    public static Binding CreateCreditCardBinding()
    {
        var httpTransport = new HttpTransportBindingElement();

        // The message security binding element will be configured to require a credit card.
        // The token that is encrypted with the service's certificate.
        var messageSecurity = new SymmetricSecurityBindingElement();
        messageSecurity.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CreditCardTokenParameters());
        X509SecurityTokenParameters x509ProtectionParameters = new X509SecurityTokenParameters();
        x509ProtectionParameters.InclusionMode = SecurityTokenInclusionMode.Never;
        messageSecurity.ProtectionTokenParameters = x509ProtectionParameters;
        return new CustomBinding(messageSecurity, httpTransport);
    }
}

Als u een creditcardtoken in het bericht wilt gebruiken, gebruikt het voorbeeld aangepaste servicereferenties om deze functionaliteit te bieden. De klasse servicereferenties bevindt zich in de CreditCardServiceCredentials klasse en wordt toegevoegd aan de gedragverzamelingen van de servicehost in de EchoServiceHost.InitializeRuntime methode.

class EchoServiceHost : ServiceHost
{
    string creditCardFile;

    public EchoServiceHost(parameters Uri[] addresses)
        : base(typeof(EchoService), addresses)
    {
        creditCardFile = ConfigurationManager.AppSettings["creditCardFile"];
        if (string.IsNullOrEmpty(creditCardFile))
        {
            throw new ConfigurationErrorsException("creditCardFile not specified in service config");
        }

        creditCardFile = String.Format("{0}\\{1}", System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath, creditCardFile);
    }

    override protected void InitializeRuntime()
    {
        // Create a credit card service credentials and add it to the behaviors.
        CreditCardServiceCredentials serviceCredentials = new CreditCardServiceCredentials(this.creditCardFile);
        serviceCredentials.ServiceCertificate.SetCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);
        this.Description.Behaviors.Remove((typeof(ServiceCredentials)));
        this.Description.Behaviors.Add(serviceCredentials);

        // Register a credit card binding for the endpoint.
        Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();
        this.AddServiceEndpoint(typeof(IEchoService), creditCardBinding, string.Empty);

        base.InitializeRuntime();
    }
}

Het clienteindpunt wordt op een vergelijkbare manier geconfigureerd als het service-eindpunt. De client gebruikt dezelfde BindingHelper klasse om een binding te maken. De rest van de installatie bevindt zich in de Client klasse. De client stelt ook gegevens in die moeten worden opgenomen in de CreditCardToken en informatie over het X.509-certificaat van de service in de installatiecode door een CreditCardClientCredentials exemplaar met de juiste gegevens toe te voegen aan het gedrag van het clienteindpuntverzameling. In het voorbeeld wordt een X.509-certificaat gebruikt waarbij de onderwerpnaam is ingesteld CN=localhost op als het servicecertificaat.

Binding creditCardBinding = BindingHelper.CreateCreditCardBinding();
var serviceAddress = new EndpointAddress("http://localhost/servicemodelsamples/service.svc");

// Create a client with given client endpoint configuration.
channelFactory = new ChannelFactory<IEchoService>(creditCardBinding, serviceAddress);

// Configure the credit card credentials on the channel factory.
var credentials =
      new CreditCardClientCredentials(
      new CreditCardInfo(creditCardNumber, issuer, expirationTime));
// Configure the service certificate on the credentials.
credentials.ServiceCertificate.SetDefaultCertificate(
      "CN=localhost", StoreLocation.LocalMachine, StoreName.My);

// Replace ClientCredentials with CreditCardClientCredentials.
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(credentials);

client = channelFactory.CreateChannel();

Console.WriteLine($"Echo service returned: {client.Echo()}");

((IChannel)client).Close();
channelFactory.Close();

Implementatie van aangepaste beveiligingstokens

Als u een aangepast beveiligingstoken in WCF wilt inschakelen, maakt u een objectweergave van het aangepaste beveiligingstoken. Het voorbeeld heeft deze weergave in de CreditCardToken klasse. De objectweergave is verantwoordelijk voor het bewaren van alle relevante beveiligingstokengegevens en voor het opgeven van een lijst met beveiligingssleutels in het beveiligingstoken. In dit geval bevat het token voor creditcardbeveiliging geen beveiligingssleutel.

In de volgende sectie wordt beschreven wat er moet worden gedaan om een aangepast token via de kabel te kunnen verzenden en te gebruiken door een WCF-eindpunt.

class CreditCardToken : SecurityToken
{
    CreditCardInfo cardInfo;
    DateTime effectiveTime = DateTime.UtcNow;
    string id;
    ReadOnlyCollection<SecurityKey> securityKeys;

    public CreditCardToken(CreditCardInfo cardInfo) : this(cardInfo, Guid.NewGuid().ToString()) { }

    public CreditCardToken(CreditCardInfo cardInfo, string id)
    {
        if (cardInfo == null)
            throw new ArgumentNullException(nameof(cardInfo));

        if (id == null)
            throw new ArgumentNullException(nameof(id));

        this.cardInfo = cardInfo;
        this.id = id;

        // The credit card token is not capable of any cryptography.
        this.securityKeys = new ReadOnlyCollection<SecurityKey>(new List<SecurityKey>());
    }

    public CreditCardInfo CardInfo { get { return this.cardInfo; } }

    public override ReadOnlyCollection<SecurityKey> SecurityKeys { get { return this.securityKeys; } }

    public override DateTime ValidFrom { get { return this.effectiveTime; } }
    public override DateTime ValidTo { get { return this.cardInfo.ExpirationDate; } }
    public override string Id { get { return this.id; } }
}

Het aangepaste creditcardtoken ophalen van en naar het bericht

Serializers voor beveiligingstokens in WCF zijn verantwoordelijk voor het maken van een objectweergave van beveiligingstokens van de XML in het bericht en het maken van een XML-vorm van de beveiligingstokens. Ze zijn ook verantwoordelijk voor andere functionaliteit, zoals het lezen en schrijven van sleutel-id's die verwijzen naar beveiligingstokens, maar in dit voorbeeld wordt alleen functionaliteit voor beveiligingstokens gebruikt. Als u een aangepast token wilt inschakelen, moet u uw eigen serialisatiefunctie voor beveiligingstokens implementeren. In dit voorbeeld wordt de CreditCardSecurityTokenSerializer klasse voor dit doel gebruikt.

In de service leest de aangepaste serialisatiefunctie de XML-vorm van het aangepaste token en wordt de weergave van het aangepaste tokenobject gemaakt.

Op de client schrijft de CreditCardSecurityTokenSerializer klasse de informatie in de objectweergave van het beveiligingstoken naar de XML-schrijver.

public class CreditCardSecurityTokenSerializer : WSSecurityTokenSerializer
{
    public CreditCardSecurityTokenSerializer(SecurityTokenVersion version) : base() { }

    protected override bool CanReadTokenCore(XmlReader reader)
    {
        XmlDictionaryReader localReader = XmlDictionaryReader.CreateDictionaryReader(reader);

        if (reader == null)
            throw new ArgumentNullException(nameof(reader));

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))
            return true;

        return base.CanReadTokenCore(reader);
    }

    protected override SecurityToken ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)
    {
        if (reader == null)
            throw new ArgumentNullException(nameof(reader));

        if (reader.IsStartElement(Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace))
        {
            string id = reader.GetAttribute(Constants.Id, Constants.WsUtilityNamespace);

            reader.ReadStartElement();

            // Read the credit card number.
            string creditCardNumber = reader.ReadElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace);

            // Read the expiration date.
            string expirationTimeString = reader.ReadElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace);
            DateTime expirationTime = XmlConvert.ToDateTime(expirationTimeString, XmlDateTimeSerializationMode.Utc);

            // Read the issuer of the credit card.
            string creditCardIssuer = reader.ReadElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace);
            reader.ReadEndElement();

            var cardInfo = new CreditCardInfo(creditCardNumber, creditCardIssuer, expirationTime);

            return new CreditCardToken(cardInfo, id);
        }
        else
        {
            return WSSecurityTokenSerializer.DefaultInstance.ReadToken(reader, tokenResolver);
        }
    }

    protected override bool CanWriteTokenCore(SecurityToken token)
    {
        if (token is CreditCardToken)
            return true;
        return base.CanWriteTokenCore(token);
    }

    protected override void WriteTokenCore(XmlWriter writer, SecurityToken token)
    {
        if (writer == null)
            throw new ArgumentNullException(nameof(writer));
        if (token == null)
            throw new ArgumentNullException(nameof(token));

        CreditCardToken c = token as CreditCardToken;
        if (c != null)
        {
            writer.WriteStartElement(Constants.CreditCardTokenPrefix, Constants.CreditCardTokenName, Constants.CreditCardTokenNamespace);
            writer.WriteAttributeString(Constants.WsUtilityPrefix, Constants.Id, Constants.WsUtilityNamespace, token.Id);
            writer.WriteElementString(Constants.CreditCardNumberElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardNumber);
            writer.WriteElementString(Constants.CreditCardExpirationElementName, Constants.CreditCardTokenNamespace, XmlConvert.ToString(c.CardInfo.ExpirationDate, XmlDateTimeSerializationMode.Utc));
            writer.WriteElementString(Constants.CreditCardIssuerElementName, Constants.CreditCardTokenNamespace, c.CardInfo.CardIssuer);
            writer.WriteEndElement();
            writer.Flush();
        }
        else
        {
            base.WriteTokenCore(writer, token);
        }
    }
}

De klassen Tokenprovider en Token Authenticator worden gemaakt

Client- en servicereferenties zijn verantwoordelijk voor het leveren van het exemplaar van de beveiligingstokenbeheer. Het exemplaar van beveiligingstokenbeheer wordt gebruikt om tokenproviders, tokenauthenators en tokenserialisaties op te halen.

De tokenprovider maakt een objectweergave van het token op basis van de informatie in de client- of servicereferenties. De objectweergave van het token wordt vervolgens naar het bericht geschreven met behulp van de tokenserialisatie (besproken in de vorige sectie).

De token authenticator valideert tokens die binnenkomen in het bericht. De binnenkomende tokenobjectweergave wordt gemaakt door de tokenserialisatiefunctie. Deze objectweergave wordt vervolgens doorgegeven aan de token authenticator voor validatie. Nadat het token is gevalideerd, retourneert de token authenticator een verzameling IAuthorizationPolicy objecten die de informatie in het token vertegenwoordigen. Deze informatie wordt later gebruikt tijdens de berichtverwerking om autorisatiebeslissingen uit te voeren en claims voor de toepassing op te geven. In dit voorbeeld gebruikt CreditCardTokenAuthorizationPolicy de creditcardtoken authenticator voor dit doel.

De tokenserialisatie is verantwoordelijk voor het ophalen van de objectweergave van het token naar en van de kabel. Dit wordt besproken in de vorige sectie.

In dit voorbeeld gebruiken we alleen een tokenprovider op de client en een tokenverificator alleen in de service, omdat we alleen een creditcardtoken willen verzenden in de richting van de client-naar-service.

De functionaliteit op de client bevindt zich in de CreditCardClientCredentialsen CreditCardClientCredentialsSecurityTokenManagerCreditCardTokenProvider klassen.

Op de service bevindt de functionaliteit zich in de CreditCardServiceCredentials, CreditCardServiceCredentialsSecurityTokenManagerCreditCardTokenAuthenticator en CreditCardTokenAuthorizationPolicy klassen.

    public class CreditCardClientCredentials : ClientCredentials
    {
        CreditCardInfo creditCardInfo;

        public CreditCardClientCredentials(CreditCardInfo creditCardInfo)
            : base()
        {
            if (creditCardInfo == null)
                throw new ArgumentNullException(nameof(creditCardInfo));

            this.creditCardInfo = creditCardInfo;
        }

        public CreditCardInfo CreditCardInfo
        {
            get { return this.creditCardInfo; }
        }

        protected override ClientCredentials CloneCore()
        {
            return new CreditCardClientCredentials(this.creditCardInfo);
        }

        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CreditCardClientCredentialsSecurityTokenManager(this);
        }
    }

    public class CreditCardClientCredentialsSecurityTokenManager : ClientCredentialsSecurityTokenManager
    {
        CreditCardClientCredentials creditCardClientCredentials;

        public CreditCardClientCredentialsSecurityTokenManager(CreditCardClientCredentials creditCardClientCredentials)
            : base (creditCardClientCredentials)
        {
            this.creditCardClientCredentials = creditCardClientCredentials;
        }

        public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
        {
            // Handle this token for Custom.
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)
                return new CreditCardTokenProvider(this.creditCardClientCredentials.CreditCardInfo);
            // Return server cert.
            else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement)
            {
                if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
                {
                    return new X509SecurityTokenProvider(creditCardClientCredentials.ServiceCertificate.DefaultCertificate);
                }
            }

            return base.CreateSecurityTokenProvider(tokenRequirement);
        }

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {

            return new CreditCardSecurityTokenSerializer(version);
        }

    }

    class CreditCardTokenProvider : SecurityTokenProvider
    {
        CreditCardInfo creditCardInfo;

        public CreditCardTokenProvider(CreditCardInfo creditCardInfo) : base()
        {
            if (creditCardInfo == null)
                throw new ArgumentNullException(nameof(creditCardInfo));

            this.creditCardInfo = creditCardInfo;
        }

        protected override SecurityToken GetTokenCore(TimeSpan timeout)
        {
            SecurityToken result = new CreditCardToken(this.creditCardInfo);
            return result;
        }
    }

    public class CreditCardServiceCredentials : ServiceCredentials
    {
        string creditCardFile;

        public CreditCardServiceCredentials(string creditCardFile)
            : base()
        {
            if (creditCardFile == null)
                throw new ArgumentNullException(nameof(creditCardFile));

            this.creditCardFile = creditCardFile;
        }

        public string CreditCardDataFile
        {
            get { return this.creditCardFile; }
        }

        protected override ServiceCredentials CloneCore()
        {
            return new CreditCardServiceCredentials(this.creditCardFile);
        }

        public override SecurityTokenManager CreateSecurityTokenManager()
        {
            return new CreditCardServiceCredentialsSecurityTokenManager(this);
        }
    }

    public class CreditCardServiceCredentialsSecurityTokenManager : ServiceCredentialsSecurityTokenManager
    {
        CreditCardServiceCredentials creditCardServiceCredentials;

        public CreditCardServiceCredentialsSecurityTokenManager(CreditCardServiceCredentials creditCardServiceCredentials)
            : base(creditCardServiceCredentials)
        {
            this.creditCardServiceCredentials = creditCardServiceCredentials;
        }

        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            if (tokenRequirement.TokenType == Constants.CreditCardTokenType)
            {
                outOfBandTokenResolver = null;
                return new CreditCardTokenAuthenticator(creditCardServiceCredentials.CreditCardDataFile);
            }

            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
        }

        public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
        {
            return new CreditCardSecurityTokenSerializer(version);
        }
    }

    class CreditCardTokenAuthenticator : SecurityTokenAuthenticator
    {
        string creditCardsFile;
        public CreditCardTokenAuthenticator(string creditCardsFile)
        {
            this.creditCardsFile = creditCardsFile;
        }

        protected override bool CanValidateTokenCore(SecurityToken token)
        {
            return (token is CreditCardToken);
        }

        protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
        {
            CreditCardToken creditCardToken = token as CreditCardToken;

            if (creditCardToken.CardInfo.ExpirationDate < DateTime.UtcNow)
                throw new SecurityTokenValidationException("The credit card has expired.");
            if (!IsCardNumberAndExpirationValid(creditCardToken.CardInfo))
                throw new SecurityTokenValidationException("Unknown or invalid credit card.");

            // the credit card token has only 1 claim - the card number. The issuer for the claim is the
            // credit card issuer

            var cardIssuerClaimSet = new DefaultClaimSet(new Claim(ClaimTypes.Name, creditCardToken.CardInfo.CardIssuer, Rights.PossessProperty));
            var cardClaimSet = new DefaultClaimSet(cardIssuerClaimSet, new Claim(Constants.CreditCardNumberClaim, creditCardToken.CardInfo.CardNumber, Rights.PossessProperty));
            var policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new CreditCardTokenAuthorizationPolicy(cardClaimSet));
            return policies.AsReadOnly();
        }

        /// <summary>
        /// Helper method to check if a given credit card entry is present in the User DB
        /// </summary>
        private bool IsCardNumberAndExpirationValid(CreditCardInfo cardInfo)
        {
            try
            {
                using (var myStreamReader = new StreamReader(this.creditCardsFile))
                {
                    string line = "";
                    while ((line = myStreamReader.ReadLine()) != null)
                    {
                        string[] splitEntry = line.Split('#');
                        if (splitEntry[0] == cardInfo.CardNumber)
                        {
                            string expirationDateString = splitEntry[1].Trim();
                            DateTime expirationDateOnFile = DateTime.Parse(expirationDateString, System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal);
                            if (cardInfo.ExpirationDate == expirationDateOnFile)
                            {
                                string issuer = splitEntry[2];
                                return issuer.Equals(cardInfo.CardIssuer, StringComparison.InvariantCultureIgnoreCase);
                            }
                            else
                            {
                                return false;
                            }
                        }
                    }
                    return false;
                }
            }
            catch (Exception e)
            {
                throw new Exception("BookStoreService: Error while retrieving credit card information from User DB " + e.ToString());
            }
        }
    }

    public class CreditCardTokenAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        ClaimSet issuer;
        IEnumerable<ClaimSet> issuedClaimSets;

        public CreditCardTokenAuthorizationPolicy(ClaimSet issuedClaims)
        {
            if (issuedClaims == null)
                throw new ArgumentNullException(nameof(issuedClaims));
            this.issuer = issuedClaims.Issuer;
            this.issuedClaimSets = new ClaimSet[] { issuedClaims };
            this.id = Guid.NewGuid().ToString();
        }

        public ClaimSet Issuer { get { return this.issuer; } }

        public string Id { get { return this.id; } }

        public bool Evaluate(EvaluationContext context, ref object state)
        {
            foreach (ClaimSet issuance in this.issuedClaimSets)
            {
                context.AddClaimSet(this, issuance);
            }

            return true;
        }
    }

De gegevens van bellers weergeven

Als u de gegevens van de aanroeper wilt weergeven, gebruikt u de ServiceSecurityContext.Current.AuthorizationContext.ClaimSets informatie die wordt weergegeven in de volgende voorbeeldcode. De ServiceSecurityContext.Current.AuthorizationContext.ClaimSets bevat autorisatieclaims die zijn gekoppeld aan de huidige aanroeper. De claims worden geleverd door de klasse in de CreditCardTokenAuthorizationPolicies verzameling.

bool TryGetStringClaimValue(ClaimSet claimSet, string claimType, out string claimValue)
{
    claimValue = null;
    IEnumerable<Claim> matchingClaims = claimSet.FindClaims(claimType, Rights.PossessProperty);
    if (matchingClaims == null)
        return false;
    IEnumerator<Claim> enumerator = matchingClaims.GetEnumerator();
    enumerator.MoveNext();
    claimValue = (enumerator.Current.Resource == null) ? null :
        enumerator.Current.Resource.ToString();
    return true;
}

string GetCallerCreditCardNumber()
{
     foreach (ClaimSet claimSet in
         ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
     {
         string creditCardNumber = null;
         if (TryGetStringClaimValue(claimSet,
             Constants.CreditCardNumberClaim, out creditCardNumber))
             {
                 string issuer;
                 if (!TryGetStringClaimValue(claimSet.Issuer,
                        ClaimTypes.Name, out issuer))
                 {
                     issuer = "Unknown";
                 }
                 return $"Credit card '{creditCardNumber}' issued by '{issuer}'";
        }
    }
    return "Credit card is not known";
}

Wanneer u het voorbeeld uitvoert, worden de bewerkingsaanvragen en -antwoorden weergegeven in het clientconsolevenster. Druk op Enter in het clientvenster om de client af te sluiten.

Batch-bestand instellen

Met het Setup.bat batchbestand dat is opgenomen in dit voorbeeld, kunt u de server configureren met relevante certificaten om de iis-gehoste toepassing uit te voeren waarvoor beveiliging op basis van servercertificaten is vereist. Dit batchbestand moet worden gewijzigd om te kunnen werken op computers of om te kunnen werken in een niet-gehost geval.

Hieronder vindt u een kort overzicht van de verschillende secties van de batchbestanden, zodat ze kunnen worden gewijzigd om te worden uitgevoerd in de juiste configuratie.

  • Het servercertificaat maken:

    Met de volgende regels van het Setup.bat batchbestand maakt u het servercertificaat dat moet worden gebruikt. De %SERVER_NAME% variabele geeft de servernaam op. Wijzig deze variabele om uw eigen servernaam op te geven. De standaardinstelling in dit batchbestand is localhost. Als u de %SERVER_NAME% variabele wijzigt, moet u de Client.cs- en Service.cs-bestanden doorlopen en alle exemplaren van localhost vervangen door de servernaam die u in het Setup.bat script gebruikt.

    Het certificaat wordt opgeslagen in mijn (persoonlijke) archief onder de LocalMachine winkellocatie. Het certificaat wordt opgeslagen in het LocalMachine-archief voor de iis-gehoste services. Voor zelf-hostende services moet u het batchbestand wijzigen om het clientcertificaat op te slaan op de locatie van het CurrentUser-archief door de tekenreeks LocalMachine te vervangen door CurrentUser.

    echo ************
    echo Server cert setup starting
    echo %SERVER_NAME%
    echo ************
    echo making server cert
    echo ************
    makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
    
  • Het servercertificaat installeren in het vertrouwde certificaatarchief van de client:

    Met de volgende regels in het Setup.bat batchbestand kopieert u het servercertificaat naar het archief vertrouwde personen van de client. Deze stap is vereist omdat certificaten die worden gegenereerd door Makecert.exe niet impliciet worden vertrouwd door het clientsysteem. Als u al een certificaat hebt dat is geroot in een vertrouwd basiscertificaat van een client, bijvoorbeeld een door Microsoft uitgegeven certificaat, is deze stap van het vullen van het clientcertificaatarchief met het servercertificaat niet vereist.

    echo ************
    echo copying server cert to client's TrustedPeople store
    echo ************
    certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
    
  • Als u toegang tot de persoonlijke sleutel van het certificaat wilt inschakelen vanuit de door IIS gehoste service, moet aan het gebruikersaccount waarop het iis-hostproces wordt uitgevoerd, de juiste machtigingen worden verleend voor de persoonlijke sleutel. Dit wordt bereikt door de laatste stappen in het Setup.bat script.

    echo ************
    echo setting privileges on server certificates
    echo ************
    for /F "delims=" %%i in ('"%ProgramFiles%\ServiceModelSampleTools\FindPrivateKey.exe" My LocalMachine -n CN^=%SERVER_NAME% -a') do set PRIVATE_KEY_FILE=%%i
    set WP_ACCOUNT=NT AUTHORITY\NETWORK SERVICE
    (ver | findstr /C:"5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
    echo Y|cacls.exe "%PRIVATE_KEY_FILE%" /E /G "%WP_ACCOUNT%":R
    iisreset
    

Notitie

Het Setup.bat batchbestand is ontworpen om te worden uitgevoerd vanaf een Visual Studio-opdrachtprompt. De omgevingsvariabele PATH die in de Visual Studio-opdrachtprompt is ingesteld, verwijst naar de map met uitvoerbare bestanden die zijn vereist voor het Setup.bat script.

Het voorbeeld instellen en bouwen

  1. Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.

  2. Volg de instructies in Het bouwen van de Windows Communication Foundation-voorbeelden om de oplossing te bouwen.

Het voorbeeld uitvoeren op dezelfde computer

  1. Open een Visual Studio-opdrachtpromptvenster met beheerdersbevoegdheden en voer Setup.bat uit vanuit de voorbeeldinstallatiemap. Hiermee worden alle certificaten geïnstalleerd die vereist zijn voor het uitvoeren van het voorbeeld. Zorg ervoor dat het pad de map bevat waarin Makecert.exe zich bevindt.

Notitie

Verwijder de certificaten door Cleanup.bat uit te voeren wanneer u klaar bent met het voorbeeld. Andere beveiligingsvoorbeelden gebruiken dezelfde certificaten.

  1. Start Client.exe vanuit de map client\bin. Clientactiviteit wordt weergegeven in de clientconsoletoepassing.

  2. Als de client en service niet kunnen communiceren, raadpleegt u Tips voor probleemoplossing voor WCF-voorbeelden.

Het voorbeeld uitvoeren op een computer

  1. Maak een map op de servicecomputer voor de binaire servicebestanden.

  2. Kopieer de programmabestanden van de service naar de servicemap op de servicecomputer. Vergeet niet om CreditCardFile.txt te kopiëren; anders kan de creditcard-verificator geen creditcardgegevens valideren die zijn verzonden vanaf de client. Kopieer ook de Setup.bat- en Cleanup.bat-bestanden naar de servicecomputer.

  3. U moet een servercertificaat hebben met de onderwerpnaam die de volledig gekwalificeerde domeinnaam van de computer bevat. U kunt er een maken met behulp van de Setup.bat als u de %SERVER_NAME% variabele wijzigt in een volledig gekwalificeerde naam van de computer waarop de service wordt gehost. Houd er rekening mee dat het Setup.bat-bestand moet worden uitgevoerd in een opdrachtprompt voor ontwikkelaars voor Visual Studio die is geopend met beheerdersbevoegdheden.

  4. Kopieer het servercertificaat naar het archief CurrentUser-Trusted Mensen op de client. U moet dit alleen doen als het servercertificaat niet is uitgegeven door een vertrouwde verlener.

  5. Wijzig in het bestand EchoServiceHost.cs de waarde van de onderwerpnaam van het certificaat om een volledig gekwalificeerde computernaam op te geven in plaats van localhost.

  6. Kopieer de clientprogrammabestanden uit de map \client\bin\ onder de taalspecifieke map naar de clientcomputer.

  7. Wijzig in het Client.cs bestand de adreswaarde van het eindpunt zodat deze overeenkomt met het nieuwe adres van uw service.

  8. Wijzig in het bestand Client.cs de onderwerpnaam van het X.509-certificaat van de service zodat deze overeenkomt met de volledig gekwalificeerde computernaam van de externe host in plaats van localhost.

  9. Start Client.exe vanaf een opdrachtpromptvenster op de clientcomputer.

  10. Als de client en service niet kunnen communiceren, raadpleegt u Tips voor probleemoplossing voor WCF-voorbeelden.

Opschonen na het voorbeeld

  1. Voer Cleanup.bat uit in de map met voorbeelden zodra u klaar bent met het uitvoeren van het voorbeeld.