如何在每个请求中将 winform 自定义用户凭据传递给 WCF 服务?

Posted

技术标签:

【中文标题】如何在每个请求中将 winform 自定义用户凭据传递给 WCF 服务?【英文标题】:How to pass winform custom user credentials to WCF services in every requests? 【发布时间】:2019-07-27 01:54:43 【问题描述】:

我想要实现的是在每个请求中将凭据/令牌传递给 WCF 服务。顺便说一句,这个凭据不是 windows 凭据,它们是从自定义数据库中获取的,并且身份验证逻辑非常简单,tenantId+username+password。

我目前正在使用消息检查器在标头中插入此类信息并从服务器端检查器获取它们(使用OperationContext)。

但为了保持线程安全,我必须将请求包装在每个 winform 请求中,如下所示:

using (new OperationContextScope((WcfService as ServiceClient).InnerChannel))

   MessageHeader hdXXId = MessageHeader.CreateHeader("XXId", "CustomHeader", WinformSomeVariable.XXId);
   OperationContext.Current.OutgoingMessageHeaders.Add(hdXXId);

   _objXX = WcfService.GetXXById(id);


如上所示,这非常繁重,显然不是处理这种情况的明智方法。那么有什么方法可以安全地保存这些信息,并且还可以在 WCF Inspectors 中获取它们?

非常感谢!

PS。感谢@Abraham Qian,我一直都很傻。只需将客户端检查器放在同一个 winform 项目中即可解决此问题。

【问题讨论】:

你看到这个问题了吗? ***.com/questions/35223163/… 那么如何实现自定义用户名/密码验证呢?如果可能,为什么不使用以下方式发送客户端凭据。 ChannelFactory factory = new ChannelFactory(binding, new EndpointAddress("localhost:11011")); factory.Credentials.UserName.UserName = "jack"; factory.Credentials.UserName.Password = "123456"; 或者客户端代理类方式,client.ClientCredentials.UserName.UserName = "jack"; client.ClientCredentials.UserName.Password = "123456"; @MohammadRezaHasanzadeh 我没有使用 Windows 身份验证。 @AbrahamQian,感谢您的建议。用户认证很简单,验证用户tenantId+username+password即可。但是使用 ChannelFactory 只提供用户名和密码,我如何传递tenantId? 这取决于您的验证设计。我希望您可以分享有关服务器端身份验证过程的更多详细信息。此外,使用 OperationContextScope 添加临时消息头在当前请求中可用,而不是在所有客户端请求中。您是否考虑过使用 IclientMessageInspector 接口来创建持久消息头,或者使用带有自定义用户名/密码身份验证的地址头重新设计身份验证? 【参考方案1】:

暂时忽略如何重构身份验证的问题。 至于如何使用 IClientMessageInspector 接口创建持久化消息头,下面的代码 sn -p 可能有用(假设使用 Channel Factory 调用)

class Program
    
        static void Main(string[] args)
        
            Uri uri = new Uri("http://localhost:1300");
            IService service = ChannelFactory<IService>.CreateChannel(new BasicHttpBinding(), new EndpointAddress(uri));
            try
            
                Console.WriteLine(service.SayHello());
            
            catch (Exception ex)
            
                Console.WriteLine(ex.ToString());
            
        
    

    [ServiceContract(Namespace = "mydomain")]
    [CustomContractBehavior]
    public interface IService
    
        [OperationContract]
        string SayHello();
    

    public class ClientMessageLogger : IClientMessageInspector
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        
            string displayText = $"the client has received the reply:\nreply\n";
            Console.Write(displayText);
        

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        
        //Add custom message header
            request.Headers.Add(MessageHeader.CreateHeader("myheader","mynamespace",2000));
            string displayText = $"the client send request message:\nrequest\n";
            Console.WriteLine(displayText);
            return null;

        
    

    public class CustomContractBehaviorAttribute : Attribute, IContractBehavior, IContractBehaviorAttribute
    
        public Type TargetContract => typeof(IService);

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        
            return;
        

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        
            clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger());
        

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        
            return;
        

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        
            return;
        
    

【讨论】:

@Abrahan Qian,感谢您的建议。我实际上已经实现了与您在上面展示的相同的设计。但这仍然不能解决我的问题。假设登录后,用户信息存储在winform中的静态类中。但ClientMessageLogger 文件位于 WCF 服务应用程序项目中。他们是2个不同的项目。现在如何将 winform 凭据传递给 WCF 服务?至于你的代码,这个硬编码部分request.Headers.Add(MessageHeader.CreateHeader("myheader","mynamespace",2000));。如何将这个 2000 从 winform 传递给检查员? 项目不需要分开,我们可以通过配置文件传递参数。 ConfigurationManager.AppSettings.Set("mykey", "11"); var 结果 = ConfigurationManager.AppSettings.GetValues("mykey")[0]; 是的!你完全正确,我真的很傻......为什么不把客户检查员放在winform项目中。我试过了,它奏效了!非常感谢!

以上是关于如何在每个请求中将 winform 自定义用户凭据传递给 WCF 服务?的主要内容,如果未能解决你的问题,请参考以下文章

如何同时从 oauth 认证两种类型的用户。并且在每个请求标头中都需要两个用户凭据

如何在 Spring Security 中自定义“错误凭据”错误响应?

WinForm里的用户自定义控件如何半透明(急急)

C#中如何实现WPF调用Winform中用户自定义的控件呢?

如何在swift中将标题视图添加到每个自定义tableViewCells

如何从自定义凭据提供程序中的更改密码场景中获取新密码