WCF中的用户验证

在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即可获取当前访问用户。

原文地址:https://www.cnblogs.com/tingqianzhu/p/8509364.html