博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于WEB Service&WCF&WebApi实现身份验证之WCF篇(2)
阅读量:5977 次
发布时间:2019-06-20

本文共 10198 字,大约阅读时间需要 33 分钟。

因前段时间工作变动(换了新工作)及工作较忙暂时中断了该系列文章,今天难得有点空闲时间,就继续总结WCF身份验证的其它方法。前面总结了三种方法(详见:),今天又将分享三种方法,完成WCF篇。

第四种:SOAP Header验证

首先定义一个WCF服务契约及服务实现类(后面的各种验证均采用该WCF服务),我这里直接采用默认的代码,如下:

服务契约定义:

namespace WcfService1{    // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”。    [ServiceContract(Namespace="http://www.zuowenjun.cn")]    public interface IService1    {        [OperationContract]        string GetData(int value);        [OperationContract]        CompositeType GetDataUsingDataContract(CompositeType composite);        // TODO: 在此添加您的服务操作    }    // 使用下面示例中说明的数据约定将复合类型添加到服务操作。    [DataContract]    public class CompositeType    {        bool boolValue = true;        string stringValue = "Hello ";        [DataMember]        public bool BoolValue        {            get { return boolValue; }            set { boolValue = value; }        }        [DataMember]        public string StringValue        {            get { return stringValue; }            set { stringValue = value; }        }    }}

服务实现Service1.svc:

namespace WcfService1{    public class Service1 : IService1    {        public string GetData(int value)        {            return string.Format("You entered: {0}", value);        }        public CompositeType GetDataUsingDataContract(CompositeType composite)        {            if (composite == null)            {                throw new ArgumentNullException("composite");            }            if (composite.BoolValue)            {                composite.StringValue += "Suffix";            }            return composite;        }    }}

 然后就开始编写实现SOAP Header验证的具体逻辑,为了便于扩展及可移植性,我这里新建一个类库项目:WcfServiceBehaviorExtension,在该项目中定义三个类,第一个是实现自IClientMessageInspector的类:AttachUserNamePasswordInspector,用于实现客户端在调用WCF服务时自动附加用户信息(用户名及密码);第二个是实现自IDispatchMessageInspector, IEndpointBehavior的类:ValidateUserNamePasswordBehavior,用于实现自定义消息分发及验证用户信息;第三个是继承自BehaviorExtensionElement的类:ValidateUserNamePasswordElement,用于实现endpointBehavior扩展,可直接配置在config文件中,若采用在代码动态添加ValidateUserNamePasswordBehavior则这类可以不用定义,下面依次分享这三个类的实现代码。

AttachUserNamePasswordInspector

namespace WcfServiceBehaviorExtension{    public class AttachUserNamePasswordInspector : IClientMessageInspector    {        private static string userName = System.Configuration.ConfigurationManager.AppSettings["username"];        private static string password = System.Configuration.ConfigurationManager.AppSettings["pwd"];        public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)        {                    }        public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)        {            MessageHeader userNameHeader = MessageHeader.CreateHeader("OperationUserName", "http://www.zuowenjun.cn", userName, false, "");            MessageHeader pwdNameHeader = MessageHeader.CreateHeader("OperationPwd", "http://www.zuowenjun.cn", password, false, "");            request.Headers.Add(userNameHeader);            request.Headers.Add(pwdNameHeader);            return null;        }    }}

ValidateUserNamePasswordBehavior

namespace WcfServiceBehaviorExtension{    public class ValidateUserNamePasswordBehavior : IDispatchMessageInspector, IEndpointBehavior    {        #region IDispatchMessageInspector 成员        private string GetHeaderValue(string key)        {            int index = OperationContext.Current.IncomingMessageHeaders.FindHeader(key, "http://www.zuowenjun.cn");            if (index >= 0)            {                return OperationContext.Current.IncomingMessageHeaders.GetHeader
(index).ToString(); } return null; } public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext) { string username = GetHeaderValue("OperationUserName"); string pwd = GetHeaderValue("OperationPwd"); if (!(username == "admin" && pwd == "wcf.admin")) { throw new FaultException("操作的用户名或密码不正确!"); } return null; } public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { } #endregion #region IEndpointBehavior 成员 public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new AttachUserNamePasswordInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ValidateUserNamePasswordBehavior()); } public void Validate(ServiceEndpoint endpoint) { } #endregion }}

ValidateUserNamePasswordElement

namespace WcfServiceBehaviorExtension{    public class ValidateUserNamePasswordElement: BehaviorExtensionElement    {        public override Type BehaviorType        {            get { return typeof(ValidateUserNamePasswordBehavior); }        }        protected override object CreateBehavior()        {            return new ValidateUserNamePasswordBehavior();        }    }}

定义好上述类后,我们再在WCF服务项目:WcfService1中引用该项目,然后修改配置文件web.config:

注意以下几点:

1.配置extensions > behaviorExtensions节点,里面添加ValidateUserNamePasswordElement类型信息,name为自定义名称,type为ValidateUserNamePasswordElement的完整类型名称,中间加逗号分隔,后面是该类所在的程序集名称;

2.配置endpointBehaviors > behavior节点,增加1中命名的节点soapHaderValidation,这里可能会报错误,但请不要理会,因为该节点在运行时才会生效的。

3.配置endpoint节点,需要添加behaviorConfiguration属性,并指定到2中所相对应的behavior

上述配置说白了就是配置自定义的服务行为类,使用在运行时注入到WCF服务管道中。

 服务端设置好后并发布运行,最后就是客户端引用该WCF服务,同时需要引用WcfServiceBehaviorExtension项目,然后修改配置文件app.config(我这里演示采用的是控制台程序):

注意事项与服务端配置文件相同,即需要配置extensions > behaviorExtensions节点、endpointBehaviors > behavior节点、endpoint节点添加behaviorConfiguration属性

另还需在appSettings节点中增加配置用户名及密码

配置好后就可以在程序中调用WCF服务,调用方法过程与普通的调用方法相同,并无其它区别。当然如果不想在客户端配置自定义节点及,可以通过以下代码来动态的添加用户名及密码信息:

static void Main(string[] args)        {            try            {                var client = new ServiceReference.Service1Client();                using (OperationContextScope contextScope = new OperationContextScope(client.InnerChannel))                {                    AppendUserInfoHeader("admin", "wcf.admin");                    string str = client.GetData(1);                    Console.WriteLine(str);                }            }            catch (Exception ex)            {                Console.WriteLine("ERROR:{0}", ex.Message);            }            Console.WriteLine("我是主线程!");            Console.Read();        }        static void AppendUserInfoHeader(string username, string pwd)        {            MessageHeader header = MessageHeader.CreateHeader("OperationUserName", "http://www.zuowenjun.cn", username);            OperationContext.Current.OutgoingMessageHeaders.Add(header);            header = MessageHeader.CreateHeader("OperationPwd", "http://www.zuowenjun.cn", pwd);            OperationContext.Current.OutgoingMessageHeaders.Add(header);        }

第五种:集成Windows用户组授权与认证

首先,在实现服务契约时,我们在需要授权与认证的类或方法中添加PrincipalPermission特性,代码如下:

[PrincipalPermission(SecurityAction.Demand,Role="Users")]        public string GetData(int value)        {            return string.Format("You entered: {0}", value);        }

这里我配置的是只有当请求的WINDOWS凭证的用户角色类型为Users才允许调用该方法,可以设置成其它角色或指定用户名(Name)等。

然后修改配置文件,配置如下:

这里需要注意,需配置serviceBehaviors > behavior > serviceAuthorization节点,将principalPermissionMode属性设为:UseWindowsGroups,并同时在service节点上指定behaviorConfiguration即可。

最后客户端正常引用该WCF服务,然后在调用WCF服务时,需要创建WindowsClientCredential对象,并指定用户名与密码,这里的用户名与密码均为该WCF服务端上服务器上的WINDOWS用户名及密码,具体代码如下:

static void Main(string[] args)        {            try            {                var client = new ServiceReference.Service1Client();                NetworkCredential credential = client.ChannelFactory.Credentials.Windows.ClientCredential;                credential.UserName = "test";                credential.Password = "test";                string str = client.GetData(1);                Console.WriteLine(str); ;            }            catch (Exception ex)            {                Console.WriteLine("ERROR:{0}", ex.Message);            }            Console.WriteLine("我是主线程!");            Console.Read();        }

第六种:集成Windows验证

服务定义与实现与文章开头贴出的代码相同,无任何特殊的地方,唯一的区别在于配置文件,如下:

注意事项:

1.绑定类型,我这里采用basicHttpBinding(不是每个绑定都支持WINDOWS验证的),同时需配置该绑定类型的security节点,mode设为TransportCredentialOnly,transport.clientCredentialType设为Windows。

完成上述配置后再直接访问WCF服务地址时,弹出需要输入用户名及密码,就表明WINDOWS验证已生效,接下来就是客户端引用该WCF服务,引用后配置文件自动进行了相应的更新,这里我们无需修改,然后在调用WCF服务时需要传入WindowsClientCredential对象,并指定用户名与密码,这里的用户名与密码均为该WCF服务端上服务器上的WINDOWS用户名及密码,与第五种相同代码就不贴出来了。

 

转载地址:http://qfsox.baihongyu.com/

你可能感兴趣的文章
Mysql常用命令
查看>>
Vuex的基本使用
查看>>
在DigitalOcean玩Kubernetes(K8S)
查看>>
python学习干货教程(11):元组
查看>>
神秘围棋AI“神之一手”:5秒一步令日本高手叹服
查看>>
vivo Y81s的usb调试模式在哪里,打开vivo Y81susb调试模式的流程
查看>>
docker-ce版本私有仓库搭建
查看>>
我的友情链接
查看>>
auto drop ssh failed ip address
查看>>
SSHv1版本的crc32漏洞
查看>>
我的友情链接
查看>>
hbase性能优化2
查看>>
Exchange 2007迁移2010后部分手机邮箱不能使用解决办法
查看>>
java try、catch、finally及finally执行顺序详解
查看>>
Operating System Concepts--chap9 Memory Management;
查看>>
ORA-01994 故障一例
查看>>
Notepad++添加右键菜单
查看>>
Java之JVM 优化经验总结
查看>>
CSS Hack 和向后兼容
查看>>
基于算法的建模---分形几何方法
查看>>