1. Базовое решение с конкатенации
Может быть самый быстрый способ и самый простой CONCATENATE Имя пользователя, SiteID и BrandID (разделенных/или - и сделать какие-то escape-последовательности, чтобы предотвратить использование разделительных символов) в заголовке Username и создать CustomValidator.
--------------------------- Редактировать ---------------- -----------
2. Есть несколько способов, чтобы пройти некоторые ** дополнительные заголовки, и использовать OperationContext
. **
Я также покажу, как поставить декларативные разрешения
Для этого вы можете использовать классы Juval Löwy. Он реализует GenericContext<T>
, который вы можете использовать.
GenericContext<T>
инкапсулирует механику доступа к заголовкам.
2,1 Создание общей библиотеки
Чтобы разделить некоторые данные от клиента и сервера, передаются как мыльные заголовки
[DataContract]
public class ExtraHeaders
{
[DataMember]
public String Username { get; set; }
[DataMember]
public String Password { get; set; }
[DataMember]
public String BranchId { get; set; }
[DataMember]
public String SiteId { get; set; }
}
2,2 На стороне клиента
Проходят дополнительные заголовки :
static void Main(string[] args)
{
// provide identity as headers
var extraHeaders = new ExtraHeaders
{
Username="manager",
Password= "password",
BranchId = "Branch2",
SiteId = "Site2"
};
MyContractClient proxy = new MyContractClient(extraHeaders);
proxy.MyMethod();
proxy.Close();
}
Прокси-сервер должен быть изменен немного (не Visual Studio или svcutil.exe поколения):
class MyContractClient : HeaderClientBase<IMyContract, ExtraHeaders>, IMyContract
{
public MyContractClient(string key,string value) : base(key,value)
{}
public void MyMethod()
{
Channel.MyMethod();
}
}
2.3 - Добавление декларативного разрешения на стороне сервера
декларативного разрешения с
[PrincipalPermission(SecurityAction.Demand, Role = "Manager")]
class MyService : IMyContract
{
[PrincipalPermission(SecurityAction.Demand, Role = "Manager")]
public void MyMethod()
{
var extraHeaders = ExtraHeadersContext.Current;
if (extraHeaders != null)
{
//Console.WriteLine("Extra headers: (BranchId:{0}, SiteId:{1}) ", extraHeaders.BranchId, extraHeaders.SiteId);
Console.WriteLine("Service call from : {{{0}}}", extraHeaders.Username);
}
}
}
2.4 Добавить serviceAuthorizationBehavior придерживаться идентичности к использованию
<behaviors>
<serviceBehaviors>
<behavior name="customIdentificationBehavior">
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Security.HttpContextPrincipalPolicy,Host" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
2.5 Внедрение услугиAuthorizationBehvior
Целью этого поведения является назначение принципала и идентификатора вызывающему.
namespace Security
{
public class HttpContextPrincipalPolicy : IAuthorizationPolicy
{
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
try
{
var extraHeaders = ExtraHeadersContext.Current;
if (extraHeaders != null)
{
IPrincipal principal = new CustomPrincipal(
new GenericIdentity(extraHeaders.Username, "Custom Provider"),extraHeaders);
evaluationContext.Properties["Principal"] = principal;
// Put user here so it can be used for declarative access on methods
evaluationContext.Properties["Identities"] = new List<IIdentity>() { principal.Identity };
}
else
{
SetAnonymousPrincipal(evaluationContext);
}
}
catch (Exception)
{
SetAnonymousPrincipal(evaluationContext);
}
return true;
}
}
}
2,6 Класс CustomPrincipal заботится сдачи пользователю в роли
public class CustomPrincipal : IPrincipal
{
private ExtraHeaders headers;
private IIdentity identity;
public CustomPrincipal(IIdentity identity, ExtraHeaders headers = null)
{
this.identity = identity;
this.headers = headers;
}
public IIdentity Identity
{
get { return identity; }
}
public bool IsInRole(string role)
{
String[] roles;
if (identity.Name == "manager")
roles = new string[1] { "Manager" };
else
roles = new string[1] { "User" };
return roles.Contains(role);
}
}
Заключение
За кулисами, классы Юваль читать (на стороне сервера) и запись (клиентская сторона).
Отрывок, например:
if(OperationContext.Current.IncomingMessageProperties.ContainsKey(ContextMessageProperty.Name))
{
ContextMessageProperty contextProperty = OperationContext.Current.IncomingMessageProperties[ContextMessageProperty.Name] as ContextMessageProperty;
if(contextProperty.Context.ContainsKey(key) == false)
{
return null;
}
return contextProperty.Context[key];
}
Ссылка на полный рабочий исходный код: http://1drv.ms/1OqPMUM
Ссылка Отлично Джувал Лоуи в: Посмотрите на «Контекст привязок как пользовательский контекст» на странице http://www.idesign.net/Downloads к имеют класс GenericContext Его книга замечательная, если вы проводите время на WCF
С уважением
Я отредактировал мое сообщение, чтобы показать вам код OperationContext/GenericContext. Надеюсь, это полезно –