在system.serviceModel的client中添加endpoint节点,设置名称、地址、bingding类型、contract契约,并使用behaviorConfiguration传递用户信息。
<endpoint name="名称" address="http://test.svc" binding="basicHttpBinding" contract="契约" behaviorConfiguration="IdentityTransfer"/>
IdentityTransfer在behaviors的endpointBehaviors中添加。
<behavior name="IdentityTransfer"> <IdentityClientTransfer/> </behavior>
IdentityClientTransfer是自定义的扩展处理,在extensions中说明:
<behaviorExtensions> <add name="IdentityClientTransfer" type="命名空间.IdentityClientTransferBehavior, 程序集"/> </behaviorExtensions>
以下直接帖相关的Class:
public class IdentityClientTransferBehavior : BehaviorExtensionElement, IEndpointBehavior { [ConfigurationProperty("authenticationType")] public string AuthenticationType { get { return (string)base["authenticationType"]; } set { base["authenticationType"] = value; } } [ConfigurationProperty("user")] public string User { get { return (string)base["user"]; } set { base["user"] = value; } } [ConfigurationProperty("password")] public string Password { get { return (string)base["password"]; } set { base["password"] = value; } } [ConfigurationProperty("domain")] public string Domain { get { return (string)base["password"]; } set { base["password"] = value; } } [ConfigurationProperty("cacheouttime", DefaultValue = 110D, IsRequired = false)] public double CacheOutTime { get { return (double)base["cacheouttime"]; } set { base["cacheouttime"] = value; } } public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { //nothing to do } public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) { if (string.IsNullOrEmpty(AuthenticationType)) clientRuntime.MessageInspectors.Add(new IdentityClientMessageInspector()); else clientRuntime.MessageInspectors.Add(new IdentityClientMessageInspector(()=>GetUserIdentity())); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { //nothing to do } public void Validate(ServiceEndpoint endpoint) { //nothing to do } protected override object CreateBehavior() { return CreateInstance(); } public override Type BehaviorType { get { return typeof(IdentityClientTransferBehavior); } } IdentityClientTransferBehavior CreateInstance() { return new IdentityClientTransferBehavior() { AuthenticationType = this.AuthenticationType, Domain = this.Domain, User = this.User, Password = this.Password, CacheOutTime = this.CacheOutTime }; } UserIdentity GetUserIdentity() { Security.Dtos.UserIdentityDto userIdnetityDto = null; switch (AuthenticationType.Trim().ToUpper()) { case AuthenticationTypes.ANONYMOUS://密码登陆 userIdnetityDto = new Security.SecurityClient().AnonymousLogin(Password); break; case AuthenticationTypes.USER_PASSWORD://用户密码登陆 userIdnetityDto = new Security.SecurityClient().LoginByUserAccount(User, Password); break; case AuthenticationTypes.ACTIVE_DIRECTORY://域账户登陆 userIdnetityDto = new Security.SecurityClient().LoginByDomainAccount(User, Password, Domain); break; case AuthenticationTypes.WINDOWS_IDENTITY://系统集成登陆 userIdnetityDto = new Security.SecurityClient().LoginByWindowsIdentity(System.Security.Principal.WindowsIdentity.GetCurrent()); break; } var userIdentity = new Security.UserIdentity(userIdnetityDto); return userIdentity; } }
[Serializable] public class SecurityClient { public UserIdentityDto AnonymousLogin(string password) { return ClientFactory.CreateClient<ISecurityProviderService>().AnonymousLogin(password); } public UserIdentityDto LoginByUserAccount(string userName, string password) { return ClientFactory.CreateClient<ISecurityProviderService>().LoginByUserAccount(userName,password); } public UserIdentityDto LoginByDomainAccount(string domainAccountName, string password, string domainName) { return ClientFactory.CreateClient<ISecurityProviderService>().LoginByDomainAccount(domainAccountName, password, domainName); } public UserIdentityDto LoginByWindowsIdentity(WindowsIdentity windowsIdentity) { return ClientFactory.CreateClient<ISecurityProviderService>(typeof(ISecurityProviderService).FullName + ".WindowsIntegration").LoginByWindowsIdentity(); } public UserPrincipalDto GetUserPrincipalByToken(string userToken) { return ClientFactory.CreateClient<ISecurityProviderService>().GetUserPrincipalByToken(userToken); } public void Logout(string userToken) { ClientFactory.CreateClient<ISecurityProviderService>().Logout(userToken); } public bool CheckUserToken(string userToken) { return ClientFactory.CreateClient<ISecurityProviderService>().CheckUserToken(userToken); } }
public class IdentityClientMessageInspector : IClientMessageInspector { private Func<UserIdentity> _getUserIdentity { get; set; } private const string USER_IDENTITY_TOKEN = "User_Identity_Token"; public IdentityClientMessageInspector() { } public IdentityClientMessageInspector(Func<UserIdentity> getUserIndentity) { _getUserIdentity = getUserIndentity; } public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel) { //If there is a user identity that be passed in, assign the current context identity as ClientUser, and then transfer it to server side; //Otherwise transfer the current context identity to server side. UserIdentity userIdentity = null; if (_getUserIdentity != null) { //Get user identity for each request to prevent from the token expiration exception userIdentity = _getUserIdentity.Invoke(); if (UserIdentity.Current != null) userIdentity.ClientUser = UserIdentity.Current.ClientUser.Clone(); } else { userIdentity = UserIdentity.Current; } //Add user identity token into message headers if (userIdentity != null) { request.Headers.Add(MessageHeader.CreateHeader( USER_IDENTITY_TOKEN, string.Empty, userIdentity.Serialize())); } return null; } }
[Serializable] public class UserIdentity : IIdentity, IDisposable { /// <summary> /// Current User Id /// </summary> public int UserId { get; set; } /// <summary> /// Current user account /// </summary> public string Account { get; set; } /// <summary> /// Current user name /// </summary> public string Name { get; set; } /// <summary> /// Current user AuthenticationType. Current custom AuthenticationType:<see cref="AuthenticationTypes"/> /// </summary> public string AuthenticationType { get; set; } /// <summary> /// Is current user authenicatd /// </summary> public bool IsAuthenticated { get; set; } /// <summary> /// Current login user's usertoken. When user hasn't login the system, the usertoken is empty. /// </summary> public string UserToken { get; set; } public bool NeedToChangePassword { get; set; } public string ClientIP { get; set; } public UserIdentity ClientUser { get; set; } /// <summary> /// Instance UserIdentity by user identity data transfer object. /// </summary> /// <param name="dto">User identity data transfer object</param> public UserIdentity(UserIdentityDto dto) { InitialUserIndentity(dto); } public UserIdentity() { } #region Login /// <summary> /// Instance UserIdentity by user account. User will call login service and login system by user account while instance UserIdenity in this mode. /// </summary> /// <param name="userName">User account name</param> /// <param name="password">Account password</param> public UserIdentity(string userName, string password) { var client = new SecurityClient(); UserIdentityDto dto = client.LoginByUserAccount(userName, password); InitialUserIndentity(dto); } /// <summary> /// Instance UserIdentity by current windows identity. User will call login service and login system by current windows identity /// while instance UserIdenity in this mode. /// </summary> /// <param name="windowsIdentity">WindowsIdentity<see cref="WindowsIdentity"/></param> public UserIdentity(WindowsIdentity windowsIdentity) { var client = new SecurityClient(); UserIdentityDto dto = client.LoginByWindowsIdentity(windowsIdentity); InitialUserIndentity(dto); } /// <summary> /// Instance UserIdentity by domain account. User will call login service and login system by domain account /// while instance UserIdenity in this mode. /// </summary> /// <param name="domainAccountName">Domain account name</param> /// <param name="password">Domain account password</param> /// <param name="domainName">Domain name</param> public UserIdentity(string domainAccountName, string password, string domainName) { var client = new SecurityClient(); UserIdentityDto dto = client.LoginByDomainAccount(domainAccountName, password, domainName); InitialUserIndentity(dto); } public UserIdentity(string password) { var client = new SecurityClient(); UserIdentityDto dto = client.AnonymousLogin(password); InitialUserIndentity(dto); } public bool CheckUserToken() { var client = new SecurityClient(); return client.CheckUserToken(this.UserToken); } public string Serialize() { return De.Framework.Utility.Serialization.XmlObjSerializer.Serialize(this); } public static UserIdentity Deserialize(string userIdentityContent) { return De.Framework.Utility.Serialization.XmlObjSerializer.Deserialize<UserIdentity>(userIdentityContent); } /// <summary> /// Get current user identity from the current user principal. /// If there is not the information, return null; /// </summary> public static UserIdentity Current { get { if (UserPrincipal.Current == null) return null; return UserPrincipal.Current.Identity as UserIdentity; } } /// <summary> /// Initial current user identity /// </summary> /// <param name="dto">User identity data transfer object</param> private void InitialUserIndentity(UserIdentityDto dto) { this.UserId = dto.UserId; this.IsAuthenticated = dto.IsAuthenticated; this.Account = dto.UserAccount; this.Name = dto.UserName; this.UserToken = dto.UserToken; this.AuthenticationType = dto.AuthenticationType; this.NeedToChangePassword = dto.NeedToChangePassword; System.Net.IPAddress[] address = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName()); if (address != null) { foreach (var item in address) { if (item.AddressFamily.Equals(AddressFamily.InterNetwork)) { this.ClientIP = item.ToString(); break; } } } if (this.ClientUser == null) this.ClientUser = this.Clone(); } /// <summary> /// Dispose current user identity and logout the system. /// </summary> public void Dispose() { //var client = new SecurityClient(); //client.Logout(UserToken); } public UserIdentity Clone() { return this.MemberwiseClone() as UserIdentity; } #endregion public static string GetClientIP() { var userIdentity = UserIdentity.Current; if (userIdentity != null && userIdentity.ClientUser != null) { return userIdentity.ClientUser.ClientIP; } return string.Empty; } }
/// <summary> /// User principal, inherit from IPrincipal.<see cref="IPrincipal"/> /// UserPrincpal contains user identity and user roles, used for authentication and authrization. /// </summary> [Serializable] public class UserPrincipal : IPrincipal, IDisposable { private const string USER_PRINCIPAL = "__USER_PRINCIPAL"; /// <summary> /// <see cref="UserIdentity"/> /// </summary> private UserIdentity _identity; /// <summary> /// <see cref="Identity"/> /// </summary> public IIdentity Identity { get { return _identity; } } private List<Role> _roles; public List<Role> Roles { get { return _roles; } set { _roles = value; } } private List<Permission> _permissions; public List<Permission> Permissions { get { return _permissions; } set { _permissions = value; } } /// <summary> /// Current login user principal. If haven't login the system, the UserPrincipal.Current is null. /// </summary> public static UserPrincipal Current { get { UserPrincipal userPrincipal = null; if (OperationUserPrincipalContext.Current != null) { userPrincipal = OperationUserPrincipalContext.Current.UserPrincipal; } else { userPrincipal = CallContext.LogicalGetData(USER_PRINCIPAL) as UserPrincipal; if (userPrincipal == null) userPrincipal = AppDomain.CurrentDomain.GetData(USER_PRINCIPAL) as UserPrincipal; } return userPrincipal; } set { if (OperationUserPrincipalContext.Current != null) { OperationUserPrincipalContext.Current.UserPrincipal = value; } else { CallContext.LogicalSetData(USER_PRINCIPAL, value); AppDomain.CurrentDomain.SetData(USER_PRINCIPAL, value); } } } /// <summary> /// Instance UserPrincipal by UserIdentity.<see cref="UserIdentity"/> /// </summary> /// <param name="userIdentity">User identity</param> /// <param name="isLoggingin">Yes:user logging in the system. No:calling service</param> public UserPrincipal(UserIdentity userIdentity) { if (userIdentity == null) throw new ArgumentNullException("userIdentity"); var client = new SecurityClient(); InitialUserPrincipal(client.GetUserPrincipalByToken(userIdentity.UserToken)); } /// <summary> /// Instance UserPrincipal by user principal data transfer object after calling the service. /// </summary> /// <param name="dto">User principal data transfer object</param> public UserPrincipal(UserPrincipalDto dto) { InitialUserPrincipal(dto); } public UserPrincipal(string userToken) { var client = new SecurityClient(); UserPrincipalDto dto = client.GetUserPrincipalByToken(userToken); if (dto != null) { _identity = new UserIdentity(dto.UserIdentityDto); InitialUserPrincipal(dto); } } /// <summary> /// Initial UserPrincipal by user principal data transfer object. /// </summary> /// <param name="dto">User principal data transfer object</param> private void InitialUserPrincipal(UserPrincipalDto dto) { _identity = new UserIdentity(dto.UserIdentityDto); if (_permissions == null) _permissions = new List<Permission>(); foreach (SecurityRoleDto securityRoleDto in dto.RoleDtoList) { var permissions = securityRoleDto.GetPermissions(); permissions.ForEach(o => _permissions.Add(new Permission(o))); } if (_roles == null) _roles = new List<Role>(); dto.RoleDtoList.ForEach(a => _roles.Add(new Role(a))); } /// <summary> /// Is current user the specified role type /// </summary> /// <param name="role">Specified role code</param> /// <returns>True, is the specified role type. else, not</returns> public bool IsInRole(string role) { return Roles.Any(o => o.Code.ToLower() == role.ToLower()); } /// <summary> /// Does current user have right to the specified system resource with the specified operation /// </summary> /// <param name="systemResourceCode">The specified system resource</param> /// <param name="systemAccessCode">The specified operation</param> /// <returns>True, has right. else, not</returns> public bool HasRight(string systemResourceCode, string systemAccessCode) { return Permissions.Any( o => o.SystemResourceCode.ToLower() == systemResourceCode.ToLower() && o.SystemAccessCode.ToLower() == systemAccessCode.ToLower()); } public void Dispose() { new SecurityClient().Logout(_identity.UserToken); } }
public class OperationUserPrincipalContext { static System.Collections.Concurrent.ConcurrentDictionary<int, OperationUserPrincipalContext> _contexts = new System.Collections.Concurrent.ConcurrentDictionary<int, OperationUserPrincipalContext>(); public UserPrincipal UserPrincipal { get; set; } public int OperationContextHashCode { get; private set; } private OperationUserPrincipalContext(int operationContextHashCode) { OperationContextHashCode = operationContextHashCode; } public static OperationUserPrincipalContext Current { get { if (OperationContext.Current == null) return null; var operationContextHashCode = OperationContext.Current.GetHashCode(); var currentContext = _contexts.GetOrAdd(operationContextHashCode, (id) => { //Listen operation completed event OperationContext.Current.OperationCompleted += (s, e) => { //Release OperationUserPrincipalContext OperationUserPrincipalContext context; _contexts.TryRemove(id, out context); }; return new OperationUserPrincipalContext(operationContextHashCode); }); return currentContext; } } }
WCF服务端直接使用UserIdentity.Current即可获取当前访问用户。