1. Solution de base avec concaténation
peut être le moyen le plus rapide et plus simple est de concatenate Nom d'utilisateur, SiteID et BrandID (séparés avec/ou - et en faisant une sorte d'échappement pour empêcher l'utilisation des caractères de séparation) dans l'nom d'utilisateur en-tête et créer un CustomValidator.
--------------------------- Modifier ---------------- -----------
2. Il y a quelques façons de passer des en-têtes supplémentaires **, et utiliser OperationContext
. **
Je vais vous montrer aussi comment mettre autorisations déclaratives
Pour ce faire, vous pouvez utiliser les classes de Juval Löwy. Il implémente un GenericContext<T>
que vous pouvez utiliser. Encapsule les mécanismes d'accès aux en-têtes.
2.1 Créer une bibliothèque partagée
Pour partager des données de client et le serveur, passés en-têtes de savon
[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 Du côté client
passer les en-têtes supplémentaires :
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();
}
La procuration doit être changé un peu (pas Visual Studio ou svcutil.exe génération):
class MyContractClient : HeaderClientBase<IMyContract, ExtraHeaders>, IMyContract
{
public MyContractClient(string key,string value) : base(key,value)
{}
public void MyMethod()
{
Channel.MyMethod();
}
}
2.3 - Ajouter la permission déclarative sur le côté serveur
autorisation déclarative avec le
[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 Ajouter un serviceAuthorizationBehavior coller une identité à l'utilisation
<behaviors>
<serviceBehaviors>
<behavior name="customIdentificationBehavior">
<serviceAuthorization principalPermissionMode="Custom">
<authorizationPolicies>
<add policyType="Security.HttpContextPrincipalPolicy,Host" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
2,5 Implémenter le serviceAuthorizationBehvior
Le but de ce comportement est d'attribuer un principal et une identité à l'appelant.
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 La classe CustomPrincipal prend soin de mettre l'utilisateur dans un rôle
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);
}
}
Conclusion
Dans les coulisses, les classes de Juval lu (côté serveur) et écrire (côté client) en-tête.
Extrait, par exemple:
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];
}
Lien vers le code source de travail complet: http://1drv.ms/1OqPMUM
Lien vers un excellent code de Juval Lowy: Rechercher des "liaisons de contexte comme contexte personnalisé" dans la page http://www.idesign.net/Downloads à avoir la classe GenericContext Son livre est génial si vous passez du temps sur WCF
Cordialement
J'ai modifié mon post pour vous montrer le code OperationContext/GenericContext. J'espère que c'est utile –