关于使用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. Invalid default value for prop "value": Props with type Object/Array must use a factory function to return the default value.(props default 数组/对象的默认值应当由一个工厂函数返回)

    Invalid default value for prop "value": Props with type Object/Array must use a factory fu ...

  2. Java分享笔记:Java网络编程--TCP程序设计

    [1] TCP编程的主要步骤 客户端(client): 1.创建Socket对象,构造方法的形参列表中需要InetAddress类对象和int型值,用来指明对方的IP地址和端口号. 2.通过Socke ...

  3. 微信小程序bindtap与catchtap的区别

    1.什么是事件 (1) 事件是视图层到逻辑层的通讯方式. (2) 事件可以将用户的行为反馈到逻辑层进行处理. (3) 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数. (4) ...

  4. 让微信内置浏览器兼容clipboard.js 复制粘贴 ios 安卓

    <!--js copy事件--><script type="text/javascript" src="/static/js/clipboard.min ...

  5. laravel -- 路由

    基本路由 Route::get('/get',function (){ return "this is get"; }); Route::post('/post',function ...

  6. Angular2中使用Jsonp

    除了引入HttpModule模块,还要引入 JsonpModule 模块 import { HttpModule, JsonpModule } from '@angular/http'; Observ ...

  7. BootCDNApi使用记录

    通过API获取BootCDN所加速的所有前端开源库的基本信息和文件列表 API 将一下API链接中的.min字样去掉后,获取到的JSON格式的返回信息是经过良好的格式化的,便于查看. 所有开源库简要信 ...

  8. [BZOJ1040][ZJOI2008]骑士(树形DP)

    对于一个联通块内,有且只有一个环,即n个点n条边 那么找到那个环,然后任意断一条边,这个联通块就变成一棵树了,然后做树形DP就行了 对于断的边要记录下来DP时特判 Code #include < ...

  9. 【SAPUI5】ODataを構成するもの

    はじめに SAPUI5でアプリケーションを作るにあたり.ODataは避けては通れないトピックです.結構広いテーマなので.5-7回くらいに分けて書きたいと思います.1回目はODataの概要について説明し ...

  10. Druid单机环境安装指南

    1.下载单机环境必备工具 下载druid-0.10.1-bin.tar.gz和tranquility-distribution-0.8.2.tgz插件 http://druid.io/download ...