WCF не предоставляет аутентификацию для каждой операции из коробки. Если вам нужны защищенные и незащищенные операции, проще всего поделить их на два сервисных контракта и предоставить каждому из них различные параметры безопасности.
Ваша идея токена авторизации уже реализована в WCF, но в вашем сценарии вы должны использовать wsHttpBinding, учетные данные клиента UserName, SecurityContext и сертификат службы.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="securedService">
<serviceCredentials>
<serviceCertificate x509FindType="FindBySubjectName" findValue="ServerCert"
storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="Secured">
<security mode="Message">
<message clientCredentialType="UserName" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="MessageSecurity.Service" behaviorConfiguration="securedService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Secured"
contract="MessageSecurity.IService">
</endpoint>
</service>
</services>
</system.serviceModel>
SecurityContext - это функционально совместимая функция, основанная на WS-SecureConversation. Это требует передачи имени пользователя и пароля только при первом вызове из экземпляра прокси-сервера (в WCF это полностью прозрачно - экземпляр прокси-клиента поддерживает контекст безопасности). При последующих вызовах используется только токен безопасности, выданный во время первого вызова. SecurityContext включен по умолчанию в wsHttpBinding.
Эта конфигурация также будет шифровать и подписывать сообщения - это полная мощность WS-Security. Любой другой подход зависит только от вас. Вам придется полностью реализовать это самостоятельно.
Вы упомянули, что у вас нет контроля над клиентами. Это не значит, что вы не можете использовать сертификат. Если вы используете сертификат, клиенты несут ответственность за его получение, если они хотят позвонить в ваш сервис. Он не имеет никакого отношения к контролю за клиентами, он касается доверия к сертификату - для общедоступной веб-службы это означает покупку сертификата в доверенном центре сертификации.
Кроме того, можно получить сервисный сертификат, не устанавливая его. Первая возможность - использовать сертификат в качестве идентификатора конечной точки. В таком случае закодированный сертификат является частью WSDL:
<wsdl:service name="Service">
<wsdl:port name="WSHttpBinding_IService" binding="tns:WSHttpBinding_IService">
<soap12:address location="http://localhost:1432/Service.svc" />
<wsa10:EndpointReference>
<wsa10:Address>http://localhost:1432/Service.svc</wsa10:Address>
<Identity xmlns="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity">
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIICmzCCAYegAwI....<X509Certificate>
</X509Data>
</KeyInfo>
</Identity>
</wsa10:EndpointReference>
</wsdl:port>
</wsdl:service>
Это выполняется автоматически, если вы указываете конечную точку wsHttpBinding с настроенным сертификатом службы и не устанавливаете ее идентификатор. Недостатком этого метода является истечение срока действия сертификата. При изменении сертификата с истекшим сроком действия все клиенты должны быть обновлены.
Вторая возможность - включить согласование учетных данных службы:
<bindings>
<wsHttpBinding>
<binding name="Secured">
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Переговоры включены по умолчанию. Он использует протокол TLSNego для обмена служебными учетными данными (сертификатом) до начала безопасной связи. Недостатком этого метода является то, что TLSNego поддерживается не всеми платформами.