关于使用SoadHeader验证Robin已经有一篇十分精彩的文章: WCF进阶:为每个操作附加身份信息, 不过我的思维方式总是跟别人有点不太一样, 还是把类似的内容用我的方式重新组织一下.

使用Header验证最直接的想法就是不要使用证书, 证书在很多场合都显得太过于复杂了, 而我们对安全性的要求并没有那么高, 毕竟我们周围的环境中有能力截取网络中的通信数据并筛选中敏感信息, 而且有动机加以利用破坏的人怎么看都像是还没出生.

下面开始演练:

打开vs, 创建一个新的WCF Service Library, 我保持了它的默认名字WcfServiceLibrary4, 然后向解决方案添加一个windows forms application, 名字为WindowsFormsApplication1, 作为我们的客户端, 在客户端添加服务引用, 直接点discover, 即可引用我们刚创建的WcfServiceLibrary4, 如图所示:

然后在客户端窗体上拖一个按钮, 给它的点击事件写两行代码以调用服务:

        private void button1_Click(object sender, EventArgs e)
{
var proxy = new ServiceReference1.Service1Client();
MessageBox.Show(proxy.GetData(3));
}

运行一下, 会看到服务被正确执行了.

现在开始添加身份验证的逻辑.  首先,  对客户端来说, 基本思想是每发出一个服务请求之前, 添加一个header, 所以就有了如下这个类:

    public class MyInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
} public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request.Headers.Add(MessageHeader.CreateHeader("Password", "gb", "123"));
return null;
}
}

这个类只是简单继承了IClientMessageInspector接口, 并添加了一个MessageHeader, 明显它不可能直接就起作用, 需要另一个机制把它与服务请求绑定起来, 于是就有了下面这个类:

    public class MyEndPointBehavior : IEndpointBehavior
{ public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyInspector());
} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
} public void Validate(ServiceEndpoint endpoint)
{
}
}

这个类负责将刚创建的Inspector添加到EndPoint的behavior当中, 但是这个类自身仍然是悬空的, 所以继续(这个类需要引用System.Configuration):

    public class MyBehaviorExtension : BehaviorExtensionElement
{ public override Type BehaviorType
{
get { return typeof(MyEndPointBehavior); }
} protected override object CreateBehavior()
{
return new MyEndPointBehavior();
}
}

再创建一个Extension类, 负责把MyEndPointBehavior类与当前的服务实例关联起来, 但是同样的问题, 这个类自身还没有被调用, ----不用再创建下一个类了, 这个类将通过app.config与服务进行绑定:

在app.config的system.serviceModel下, 添加一个自定义的behavior:

然后将已有的endPoint与此behavior关联起来:

此EndPoint的配置中只有蓝框里面是手动新增的, 其它都是自动生成. 现在这个空的behavior已经被应用到了具体的endpoint, 接下来需要把这个behavior具体化, 先来增加一个extension:

    <extensions>
<behaviorExtensions>
<add name="myExtension" type="WindowsFormsApplication1.MyBehaviorExtension, WindowsFormsApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>

需要注意的是, 这个extension的type必须是我们刚才最后添加的那个MyBehaviorExtension类的AssemblyQualifiedName, 并且中间不允许有任何的空格, 回车等.

接下来, 将这个extension与空的behavior关联起来:

关联的方法很简单, 就是增加一个节点, 名字就是新增加的extension的Name.

现在, 我们终于全线贯通了, 出发点是endpoint, 为默认的endpoint增加一个behavior, 这个behavior有一个我们自定义的extension, 这个extension会创建一个自定义的endpointbehavior, 在这里最终添加了inspector.  来测试一下吧: 在inspector中下一个断点, 执行程序, 会发现断点确实被执行了, 至此, 客户端的配置就结束了, 每一次调用服务时, 都会附加一个名为Password的header, 这就是我们的目的.

然后是服务端, 服务端需要检测是否传递了password, password的值是否正确, 如果正确才会继续提供服务. 总的流程与客户端基本一致, 唯一的区别是将IClientMessageInspector换成了IDispatchMessageInspector, 具体的几个类的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration; namespace WcfServiceLibrary4
{
class MyInspector : IDispatchMessageInspector
{ public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
if (request.Headers.FindHeader("Password", "gb") < 0 ||
request.Headers.GetHeader<string>("Password", "gb") != "123")
throw new UnauthorizedAccessException();
return null;
} public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
} public class MyEndPointBehavior : IEndpointBehavior
{ public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
} public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
} public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MyInspector());
} public void Validate(ServiceEndpoint endpoint)
{
}
} public class MyBehaviorExtension : BehaviorExtensionElement
{ public override Type BehaviorType
{
get { return typeof(MyEndPointBehavior); }
} protected override object CreateBehavior()
{
return new MyEndPointBehavior();
}
} }

App.config 的配置和客户端基本上完全相同, 只有最终的extension的type换成服务端的类型全名即可.

然后重新运行项目, 在服务端的检查口令的地方下个断点, 可以确定这里被运行到了,  这就全部完工了.

当然, 也可以把这服务端和客户端总共用到的三个接口, 一个基类全部合在一个类中实现, (比如Robin的实现) 这样可以在客户端和服务端之间共享代码, 以及类名就只剩一个了,  不过我觉得还是按它本来的面目拆开来写比较容易理解, 至于理解了之后如何优化, 那就完全自由发挥了.

WCF身份验证三:自定义身份验证之<MessageHeader>的更多相关文章

  1. jQuery Validate 表单验证插件----自定义一个验证方法

    一.下载依赖包 网盘下载:https://yunpan.cn/cryvgGGAQ3DSW  访问密码 f224 二.引入依赖包 <script src="../../scripts/j ...

  2. EasyUI表单验证,自定义插件验证,自定义js插件验证,远程验证,常见手机号,中英文,qq等验证规则验证

     { field : 'startPort', title : "起始端口", editor: "text", width : 50, editor: { ...

  3. jQuery Validation Engine 表单验证,自定义规则验证方法

    jQuery Validation Engine 表单验证说明文档http://code.ciaoca.com/jquery/validation-engine/ js加到jquery.validat ...

  4. ExtJs 自定义Vtype验证

    最近公司开发项目在用ExtJs,碰到验证的就大概的总结了一些常用的验证.自定义的验证主要有两种方式:一种是单字段的自定义验证,另一种是多字段间的验证.对于单字段的验证主要通过regex配置项指定自定义 ...

  5. MVC身份验证.MVC过滤器.MVC6关键字Task,Async.前端模拟表单验证,提交.自定义匿名集合.Edge导出到Excel.BootstrapTree树状菜单的全选和反选.bootstrap可搜索可多选可全选下拉框

    1.MVC身份验证. 有两种方式.一个是传统的所有控制器继承自定义Control,然后再里面用MVC的过滤器拦截.所以每次网站的后台被访问时.就会先走入拦截器.进行前端和后端的验证 一个是利用(MVC ...

  6. webservice安全性之 SoapHeader自定义身份验证

    相信很多开发者都用过WebService来实现程序的面向服务,本文主要介绍WebService的身份识别实现方式,当然本文会提供一个不是很完善的例子,权当抱砖引玉了. 首先我们来介绍webservic ...

  7. socketserver模块三次登陆验证,身份验证

    帅爆太阳的男人 1,socketserver是解决TCP服务器和多个客户端进行通信 服务器: import socketserver class MySocket(socketserver,BaseR ...

  8. SSL/TLS/WTLS原理(密钥协商的形象化比喻:验证服务器的身份,用服务器的公钥协商加密格式,然后再加密具体的消息,TCP传递SSL处理后的数据)good

    一 前言 首先要澄清一下名字的混淆: 1 SSL(Secure Socket Layer)是netscape公司设计的主要用于web的安全传输协议.这种协议在WEB上获得了广泛的应用. 2 IETF( ...

  9. [置顶] Web用户的身份验证及WebApi权限验证流程的设计和实现 (不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!!)

     转发 http://blog.csdn.net/besley/article/details/8516894 不是Token驗證!!!不是Token驗證!!!都是基於用户身份的票据信息驗證!!! [ ...

  10. WCF 安全性 之 自定义证书验证

    案例下载 http://download.csdn.net/detail/woxpp/4113172 客户端调用代码 通过代理类 代理生成 参见 http://www.cnblogs.com/woxp ...

随机推荐

  1. poj_2773_Happy 2006

    Two positive integers are said to be relatively prime to each other if the Great Common Divisor (GCD ...

  2. shell的命令格式

    参考高峻峰 著 循序渐进Linux(第二版) command [options] [arguments] command:表示命令的名称 options:表示命令的选项 arguments:表示命令的 ...

  3. docker搭建基于percona-xtradb-cluster方案的mysql集群

    一.部署环境 序号 hostname ip 备注 1 manager107 10.0.3.107 centos7;3.10.0-957.1.3.el7.x86_64 2 worker68 10.0.3 ...

  4. wampserver 服务器报500错误,侦察小结

    Internal Server Error The server encountered an internal error or misconfiguration and was unable to ...

  5. php 微信客服信息推送失败 微信重复推送客服消息 40001 45047

    /*** * 微信客服发送信息 * 微信客服信息推送失败 微信重复推送客服消息 40001 45047 * 递归提交到微信 直到提交成功 * @param $openid * @param int $ ...

  6. scala成长之路(1)基本语法和数据类型

    scala作为JVM上的Lisp,是一种geek类型的编程语言,也一直是我等java程序员眼中的梦寐以求的一门技能,遂下定决心花一段时间好好学习scala.第一天学习,主要介绍与java在编程上的主要 ...

  7. PADS快捷键

    问:在pads layout中怎样显示或隐藏铺铜的效果 答: 无模命令:po 或者spo 前者是平面层 后者是混合层. 同时你可以在ctrl+alt+c 色彩项中关闭 copper . 使用 无模命令 ...

  8. 嵌入式框架Zorb Framework搭建二:环形缓冲区的实现

    我是卓波,我是一名嵌入式工程师,我万万没想到我会在这里跟大家吹牛皮. 嵌入式框架Zorb Framework搭建过程 嵌入式框架Zorb Framework搭建一:嵌入式环境搭建.调试输出和建立时间系 ...

  9. mybatis报表,动态列与查询参数+行列转换

    这是报表原型,在这张报表中,使用了动态的列与动态查询参数,动态列与动态查询参数全部使用map将参数传入 map参数: //拼接查询时间 for (String month : monthList) { ...

  10. 分布式系统的CAP(Redis)

    CAP理论就是说在分布式存储系统中,最多只能实现上面的两点.而由于当前的网络硬件肯定会出现延迟丢包等问题,所以 分区容忍性是我们必须需要实现的. 所以我们只能在一致性和可用性之间进行权衡,没有NoSQ ...