Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом примере демонстрируется, как добавить пользовательскую реализацию токена в приложение Windows Communication Foundation (WCF). В этом примере используется CreditCardToken для безопасной передачи сведений о клиентских кредитных картах в сервис. Маркер передается в заголовке сообщения WS-Security и подписывается и шифруется с помощью элемента привязки симметричного безопасности вместе с текстом сообщения и другими заголовками сообщений. Это полезно в случаях, когда встроенные токены недостаточны. В этом примере показано, как предоставить пользовательский маркер безопасности службе вместо использования одного из встроенных маркеров. Служба реализует контракт, определяющий шаблон связи с запросом и ответом.
Замечание
Процедура установки и инструкции по сборке для этого примера находятся в конце этого раздела.
В этом примере показано следующее:
Как клиент может передать в службу пользовательский маркер безопасности.
Как служба может использовать и проверять пользовательский маркер безопасности.
Как код службы WCF может получить сведения о полученных токенах безопасности, включая пользовательский токен безопасности.
Как сертификат X.509 сервера используется для защиты симметричного ключа, используемого для шифрования сообщений и подписи.
Проверка подлинности клиента с помощью пользовательского токена безопасности
Служба предоставляет одну конечную точку, которая создается программно с помощью классов BindingHelper и EchoServiceHost. Конечная точка состоит из адреса, привязки и контракта. Привязка настраивается с помощью пользовательской привязки с использованием SymmetricSecurityBindingElement и HttpTransportBindingElement. В этом примере SymmetricSecurityBindingElement используется для применения сертификата X.509 службы, чтобы защитить симметричный ключ во время передачи, и передачи пользовательского CreditCardToken в заголовке сообщения WS-Security в качестве подписанного и зашифрованного токена безопасности. Поведение определяет учетные данные сервиса, которые должны быть использованы для аутентификации клиента, а также информацию о сертификате X.509 сервиса.
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);
}
}
Чтобы использовать токен кредитной карты в сообщении, в примере используются пользовательские учетные данные службы для предоставления этой функциональности. Класс учетных данных службы находится в классе CreditCardServiceCredentials и добавляется в коллекции поведения узла службы в методе EchoServiceHost.InitializeRuntime.
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();
}
}
Конечная точка клиента настраивается аналогично конечной точке службы. Клиент использует тот же BindingHelper класс для создания привязки. Остальная часть настройки находится в Client классе. Клиент также задает сведения, которые должны содержаться в CreditCardToken, и информацию о сертификате службы X.509 в коде установки, добавив экземпляр CreditCardClientCredentials с соответствующими данными в коллекцию поведения конечных точек клиента. В примере используется сертификат X.509 с именем субъекта, установленным на CN=localhost, в качестве сертификата службы.
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();
Реализация пользовательского токена безопасности
Чтобы включить пользовательский маркер безопасности в WCF, создайте объектное представление пользовательского маркера безопасности. Пример имеет это представление в CreditCardToken классе. Представление объекта отвечает за хранение всех соответствующих сведений маркера безопасности и предоставление списка ключей безопасности, содержащихся в маркере безопасности. В этом случае маркер безопасности кредитной карты не содержит ключа безопасности.
В следующем разделе описывается, что необходимо сделать, чтобы обеспечить передачу пользовательского токена по сети и его потребление конечной точкой WCF.
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; } }
}
Получение пользовательского токена кредитной карты в сообщение и из сообщения
Сериализаторы маркеров безопасности в WCF отвечают за создание объекта маркеров безопасности из XML в сообщении и создание XML-формы маркеров безопасности. Они также отвечают за другие функции, такие как чтение и запись идентификаторов ключей, указывающих на маркеры безопасности, но в этом примере используются только функциональные возможности, связанные с маркерами безопасности. Чтобы включить пользовательский токен, необходимо разработать собственный сериализатор токенов безопасности. В этом примере используется CreditCardSecurityTokenSerializer класс для этой цели.
В службе пользовательский сериализатор считывает XML-форму пользовательского токена и создает из неё объектное представление пользовательского токена.
На клиенте CreditCardSecurityTokenSerializer класс записывает сведения, содержащиеся в представлении объекта маркера безопасности, в модуль записи XML.
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);
}
}
}
Как создаются классы поставщика токенов и аутентификатора токенов
Учетные данные клиента и службы отвечают за предоставление экземпляра менеджера токенов безопасности. Экземпляр диспетчера токенов безопасности используется для получения поставщиков токенов, аутентификаторов токенов и сериализаторов токенов.
Поставщик токенов создает объектное представление токена на основе информации, содержащейся в учетных данных клиента или учетных данных службы. Затем представление объекта токена записывается в сообщение с помощью сериализатора маркеров (описано в предыдущем разделе).
Аутентификатор проверяет токены, поступающие в сообщение. Представление объекта входящего маркера создается сериализатором маркеров. Затем это представление объекта передается в аутентификатор токенов для проверки. После успешной проверки маркера аутентификатор возвращает коллекцию IAuthorizationPolicy объектов, представляющих сведения, содержащиеся в маркере. Эта информация используется позже во время обработки сообщений для принятия решений по авторизации и предоставления утверждений для приложения. В этом примере средство проверки подлинности использует маркер кредитной карты CreditCardTokenAuthorizationPolicy для этой цели.
Сериализатор токенов отвечает за получение и передачу объектного представления токена через сеть. Это рассматривается в предыдущем разделе.
В этом примере мы используем поставщик токенов только на стороне клиента и токен аутентификации только на стороне службы, так как мы хотим передать токен кредитной карты только в направлении от клиента к службе.
Функциональные возможности клиента находятся в классах CreditCardClientCredentials, CreditCardClientCredentialsSecurityTokenManager и CreditCardTokenProvider.
На сервисе функциональность находится в классах CreditCardServiceCredentials, CreditCardServiceCredentialsSecurityTokenManager, CreditCardTokenAuthenticator и CreditCardTokenAuthorizationPolicy.
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;
}
}
Отображение сведений абонентов
Чтобы отобразить сведения вызывающего абонента, используйте ServiceSecurityContext.Current.AuthorizationContext.ClaimSets приведенный ниже пример кода. Элемент ServiceSecurityContext.Current.AuthorizationContext.ClaimSets содержит утверждения о правах доступа, связанные с текущим вызывающим. Утверждения предоставляются классом CreditCardToken в коллекции AuthorizationPolicies.
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";
}
При запуске примера запросы и ответы операции отображаются в окне консоли клиента. Нажмите клавишу ВВОД в окне клиента, чтобы завершить работу клиента.
Настройка пакетного файла
Пакетный файл Setup.bat, включенный в этот пример, позволяет настроить сервер с соответствующими сертификатами для запуска размещенного в IIS приложения, требующего безопасности на основе сертификатов сервера. Для работы этого пакетного файла на разных компьютерах или без хостинга его необходимо изменить.
Ниже представлены общие сведения о различных разделах пакетных файлов, позволяющие изменять их для выполнения в соответствующей конфигурации.
Создание сертификата сервера:
В следующих строках из
Setup.batпакетного файла создается используемый сертификат сервера. Переменная%SERVER_NAME%задает имя сервера. Измените эту переменную, чтобы указать собственное имя сервера. Значение по умолчанию в этом пакетном файле — localhost. При изменении%SERVER_NAME%переменной необходимо пройти через файлы Client.cs и Service.cs и заменить все упоминания localhost на имя сервера, которое вы используете в скрипте Setup.bat.Сертификат хранится в хранилище Мой (Личное) в местоположении
LocalMachineхранилища. Сертификат хранится в хранилище LocalMachine для служб, размещенных в IIS. Для услуг с самостоятелной установкой следует изменить пакетный файл, чтобы клиентский сертификат сохранялся в расположении хранилища CurrentUser, заменив строку LocalMachine на 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Установка сертификата сервера в доверенное хранилище сертификатов клиента:
Следующие строки в пакетном файле Setup.bat копируют сертификат сервера в хранилище доверенных пользователей клиента. Этот шаг необходим, так как сертификаты, созданные Makecert.exe, не являются неявно доверенными клиентской системой. Если у вас уже есть сертификат, основанный на доверенном корневом сертификате клиента, например, выданный корпорацией Майкрософт, этот шаг, в котором хранилище сертификатов клиента заполняется серверным сертификатом, не требуется.
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Чтобы предоставить доступ к закрытому ключу сертификата из службы, размещенной в IIS, необходимо предоставить учетной записи пользователя, под которой работает процесс IIS, соответствующие разрешения для этого ключа. Это достигается последними шагами в скрипте Setup.bat.
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
Замечание
Пакетный файл Setup.bat предназначен для запуска из командной строки Visual Studio. Переменная среды PATH в командной строке Visual Studio указывает на каталог, содержащий исполняемые файлы, необходимые скрипту Setup.bat.
Для настройки и сборки примера
Убедитесь, что вы выполнили процедуру настройки One-Time для образцов Windows Communication Foundation.
Чтобы создать решение, следуйте инструкциям по созданию примеров Windows Communication Foundation.
Запуск примера на том же компьютере
- Откройте окно командной строки Visual Studio с правами администратора и запустите Setup.bat из папки установки примера. При этом устанавливаются все сертификаты, необходимые для выполнения примера. Убедитесь, что путь содержит папку, в которой находится Makecert.exe.
Замечание
Не забудьте удалить сертификаты, выполнив Cleanup.bat после завершения работы с примером. Другие примеры безопасности используют те же сертификаты.
Запустите Client.exe из каталога client\bin. Действие клиента отображается в клиентском консольном приложении.
Если клиент и служба не могут взаимодействовать, см. рекомендации по устранению неисправностей для примеров WCF.
Запуск примера на компьютере
Создайте каталог на компьютере сервиса для файлов двоичного кода сервиса.
Скопируйте файлы программы службы в каталог службы на компьютере службы. Не забудьте скопировать CreditCardFile.txt; в противном случае средство проверки подлинности кредитной карты не может проверить данные кредитной карты, отправленные клиентом. Кроме того, скопируйте файлы Setup.bat и Cleanup.bat на компьютер службы.
У вас должен быть сертификат сервера с именем субъекта, который содержит полное доменное имя компьютера. Вы можете создать его с использованием Setup.bat, если заменить переменную
%SERVER_NAME%на полное имя компьютера, на котором размещена служба. Обратите внимание, что файл Setup.bat должен выполняться в командной строке разработчика для Visual Studio, открываемой с правами администратора.Скопируйте сертификат сервера в хранилище CurrentUser-TrustedPeople на клиенте. Это необходимо сделать, только если сертификат сервера не выдан доверенным издателем.
В файле EchoServiceHost.cs измените значение имени субъекта сертификата, чтобы указать полностью квалифицированное имя компьютера вместо localhost.
Скопируйте файлы клиентской программы из папки \client\bin\ в папку, соответствующую конкретному языку, на клиентский компьютер.
В файле Client.cs измените значение адреса конечной точки, чтобы он соответствовал новому адресу службы.
В файле Client.cs измените имя владельца сертификата службы X.509 так, чтобы оно совпадало с полным квалифицированным именем компьютера удаленного хоста вместо localhost.
На клиентском компьютере запустите Client.exe из окна командной строки.
Если клиент и служба не могут взаимодействовать, см. рекомендации по устранению неисправностей для примеров WCF.
Очистка после образца
- Запустите Cleanup.bat в папке примеров после завершения работы примера.