Практическое руководство. Создание пользовательского диспетчера авторизации для службы
Инфраструктура модели удостоверений в Windows Communication Foundation (WCF) поддерживает расширяемую модель авторизации на основе утверждений. Утверждения извлекаются из маркеров, дополнительно обрабатываемых пользовательской политикой авторизации, и затем помещаются в контекст AuthorizationContext. Диспетчер авторизации проверяет утверждения в контексте AuthorizationContext для принятия решений об авторизации.
По умолчанию решения об авторизации принимаются классом ServiceAuthorizationManager; однако эти решения можно переопределить, создав пользовательский диспетчер авторизации. Чтобы создать пользовательский диспетчер авторизации, создайте класс, наследующий от класса ServiceAuthorizationManager, и реализуйте метод CheckAccessCore. Решения об авторизации принимаются в методе CheckAccessCore, который возвращает true
, если доступ предоставлен, и false
, если в доступе отказано.
Если решение об авторизации зависит от содержимого тела сообщения, используйте метод CheckAccess.
В связи с вопросами производительности при возможности следует внести изменения в приложение, чтобы решение об авторизации не требовало доступа к телу сообщения.
Пользовательский диспетчер авторизации для службы можно зарегистрировать в коде или конфигурации.
Создание пользовательского диспетчера авторизации
Создайте класс, производный от класса ServiceAuthorizationManager.
public class MyServiceAuthorizationManager : ServiceAuthorizationManager {
Public Class MyServiceAuthorizationManager Inherits ServiceAuthorizationManager
Переопределите метод CheckAccessCore(OperationContext).
Для принятия решения об авторизации используйте метод OperationContext, передаваемый в метод CheckAccessCore(OperationContext).
В следующем примере кода метод FindClaims(String, String) используется для поиска пользовательского утверждения
http://www.contoso.com/claims/allowedoperation
и принятия решения об авторизации.protected override bool CheckAccessCore(OperationContext operationContext) { // Extract the action URI from the OperationContext. Match this against the claims // in the AuthorizationContext. string action = operationContext.RequestContext.RequestMessage.Headers.Action; // Iterate through the various claim sets in the AuthorizationContext. foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets) { // Examine only those claim sets issued by System. if (cs.Issuer == ClaimSet.System) { // Iterate through claims of type "http://www.contoso.com/claims/allowedoperation". foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty)) { // If the Claim resource matches the action URI then return true to allow access. if (action == c.Resource.ToString()) return true; } } } // If this point is reached, return false to deny access. return false; }
Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean ' Extract the action URI from the OperationContext. Match this against the claims. ' in the AuthorizationContext. Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action ' Iterate through the various claimsets in the AuthorizationContext. Dim cs As ClaimSet For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets ' Examine only those claim sets issued by System. If cs.Issuer Is ClaimSet.System Then ' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation". Dim c As Claim For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _ Rights.PossessProperty) ' If the Claim resource matches the action URI then return true to allow access. If action = c.Resource.ToString() Then Return True End If Next c End If Next cs ' If this point is reached, return false to deny access. Return False End Function
Регистрация пользовательского диспетчера авторизации с помощью кода
Создайте экземпляр пользовательского диспетчера авторизации и назначьте его свойству ServiceAuthorizationManager.
Доступ к поведению ServiceAuthorizationBehavior возможен с помощью свойства Authorization.
В следующем примере кода регистрируется пользовательский диспетчер авторизации
MyServiceAuthorizationManager
.// Add a custom authorization manager to the service authorization behavior. serviceHost.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
' Add a custom authorization manager to the service authorization behavior. serviceHost.Authorization.ServiceAuthorizationManager = _ New MyServiceAuthorizationManager()
Регистрация пользовательского диспетчера авторизации с помощью конфигурации
Откройте файл конфигурации службы.
<Добавьте службуAuthorization> в< поведение>.
<В службу ServiceAuthorization> добавьте
serviceAuthorizationManagerType
атрибут и задайте его значение типу, представляющего пользовательский диспетчер авторизации.Добавьте привязку, обеспечивающую безопасность связи между клиентом и службой.
Привязка, выбранная для этой связи, определяет утверждения, добавляемые в контекст AuthorizationContext и используемые пользовательским диспетчером авторизации для принятия решений об авторизации. Дополнительные сведения о предоставленных системой привязках см. в разделе "Предоставленные системой привязки".
Свяжите поведение с конечной точкой службы, добавив элемент службы> и задайте значение
behaviorConfiguration
атрибута имени для <элемента поведения>.<Дополнительные сведения о настройке конечной точки службы см. в статье "Практическое руководство. Создание конечной точки службы в конфигурации".
В следующем примере кода регистрируется пользовательский диспетчер авторизации
Samples.MyServiceAuthorizationManager
.<configuration> <system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding_Calculator" contract="Microsoft.ServiceModel.Samples.ICalculator" /> </service> </services> <bindings> <WSHttpBinding> <binding name = "wsHttpBinding_Calculator"> <security mode="Message"> <message clientCredentialType="Windows"/> </security> </binding> </WSHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior name="CalculatorServiceBehavior"> <serviceAuthorization serviceAuthorizationManagerType="Samples.MyServiceAuthorizationManager,MyAssembly" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Предупреждение
Обратите внимание, что при указании serviceAuthorizationManagerType строка должна содержать полное имя типа. запятая и имя сборки, в которой определен тип. Если опустить имя сборки, WCF попытается загрузить тип из System.ServiceModel.dll.
Пример
В следующем образце кода показана базовая реализация класса ServiceAuthorizationManager, которая содержит переопределение метода CheckAccessCore. В этом примере кода производится проверка AuthorizationContext на наличие пользовательского утверждения и возвращается true
, если ресурс для этого пользовательского утверждения соответствует значению действия из контекста OperationContext. Более полную реализацию ServiceAuthorizationManager класса см. в разделе "Политика авторизации".
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
// Extract the action URI from the OperationContext. Match this against the claims
// in the AuthorizationContext.
string action = operationContext.RequestContext.RequestMessage.Headers.Action;
// Iterate through the various claim sets in the AuthorizationContext.
foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
{
// Examine only those claim sets issued by System.
if (cs.Issuer == ClaimSet.System)
{
// Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
{
// If the Claim resource matches the action URI then return true to allow access.
if (action == c.Resource.ToString())
return true;
}
}
}
// If this point is reached, return false to deny access.
return false;
}
}
Public Class MyServiceAuthorizationManager
Inherits ServiceAuthorizationManager
Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean
' Extract the action URI from the OperationContext. Match this against the claims.
' in the AuthorizationContext.
Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
' Iterate through the various claimsets in the AuthorizationContext.
Dim cs As ClaimSet
For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
' Examine only those claim sets issued by System.
If cs.Issuer Is ClaimSet.System Then
' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
Dim c As Claim
For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _
Rights.PossessProperty)
' If the Claim resource matches the action URI then return true to allow access.
If action = c.Resource.ToString() Then
Return True
End If
Next c
End If
Next cs
' If this point is reached, return false to deny access.
Return False
End Function
End Class