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

首先我们来介绍webservice下的两种验证方式,

一.通过集成windows身份验证

通过集成windows方式解决webservice的安全问题是一个很简洁,并且行之有效的解决方案,该方案的优点是比较安全,性能较好,当然因为与windows紧密的结合到了一起,缺点自然也很明显了,第一,不便于移植,第二,要进行相关的配置部署工作(当然我们也可以用代码来操作IIS,只不过比较麻烦,最近一直做自动化部署,所以一讲到配置马上就会联想到怎么去自动部署)

具体怎么做呢?

服务器端:配置IIS虚拟目录为集成windows身份验证

客户端:

Service1 wr = new Service1(); //web service实例

wr.Credentials = new NetworkCredential("administrator","123"); //用户名密码

lblTest.Text = wr.Add(2,2).ToString(); //调用Add的 web service方法

二.使用 SoapHeader(SOAP 标头)自定义身份验证

SoapHeader 多数情况下用来传递用户身份验证信息,当然它的作用远不止如此,有待于在实际应用中发掘,体可以实现哪些东西大家有想法可以留言一起交流.

SoapHeader 使用步骤:
(1) 创建继承自 System.Web.WebServices.SoapHeader 的自定义 SoapHeader 类型。
(2) 在 WebService 中创建拥有 public 访问权限的自定义 SoapHeader 字段。
(3) 在需要使用 SoapHeader 的 WebMethod 上添加 SoapHeaderAttribute 访问特性。SoapHeaderAttribute 构造必须指定 memberName 参数,就是我们在第二步中申明的字段名称。
(4) 生成器会自动为客户端生成同名的自定义 SoapHeader 类型,只不过比起我们在 WebService 端创建的要复杂一些。同时还会为代理类型添加一个 soapheaderValue 属性。

下面展示一段SoapHeader的代码,多余的方法将会在后面用到

客户端:

class Program
{
static void Main(string[] args)
{
Service1 ws = new Service1();
ServiceCredential mycredential = new ServiceCredential(); mycredential.User = "gazi";
mycredential.Password="gazi";
ws.ServiceCredentialValue = mycredential;
string mystr=ws.SayHello();
}
}

服务端

public class Service1 : System.Web.Services.WebService
{
public ServiceCredential myCredential; [WebMethod]
[SoapHeader("myCredential", Direction = SoapHeaderDirection.In)]
public string SayHello()
{
return "hello";
}
} public class ServiceCredential : SoapHeader
{
public string User;
public string Password;
public static bool ValideUser(string User,string Password)
{
return true;
}
public static void CheckUser(Object sender, WebServiceAuthenticationEvent e)
{
if (ValideUser(e.User, e.Password))
{
return;
}
else
{
WebServiceAuthenticationModule module = sender as WebServiceAuthenticationModule;
module.Result.AddRule("验证错误", "不能确认您的身份,请检查用户名和密码");
}
}
}

当我们拥有很多个类的时候,要添加一个或者删除一个验证方式(假设需要进行多种认证)是非常麻烦的,我们不可能跑到每个方法里面去加一个方法调用,这是灾难性的工作,当然我们也可以用AOP来实现,Aop的话需要额外增加很多代码或者直接引入第三方来做,但是我们可不可以有更简便的方法呢?

OK,答案就是使用HttpModule,我们集成IHttpModule写一个处理模块,那么它的原理是什么呢?具体进行了哪些操作呢?我们的思路如下:

  1. HTTP Module 分析 HTTP 消息以检查它们是不是 SOAP 消息。
  2. 如果 HTTP Module 检测到 SOAP 消息,它会读取 SOAP 标头。
  3. 如果 SOAP 消息的 SOAP 标头中有身份验证凭据,HTTP Module 将引发一个自定义 global.asax 事件。
 

下面来看看我们的Module代码

  1 public class WebServiceAuthenticationModule : IHttpModule
{
private static WebServiceAuthenticationEventHandler
_eventHandler = null;
/// <summary>
/// 验证事件.绑定到此事件可进行对用户身份的识别
/// </summary>
public static event WebServiceAuthenticationEventHandler Authenticate
{
add { _eventHandler = value; }
remove { _eventHandler -= value; }
}
public Result Result = new Result(); public void Dispose()
{
}
public void Init(HttpApplication app)
{
app.AuthenticateRequest = new
EventHandler(this.OnEnter);
Result.EndValid = new
EventHandler(this.OnCheckError);
} /// <summary>
/// 验证用户身份
/// </summary>
/// <param name="e"></param>
private void OnAuthenticate(WebServiceAuthenticationEvent e)
{
if (_eventHandler == null)
return; _eventHandler(this, e);
if (e.User != null)
e.Context.User = e.Principal;
} public string ModuleName
{
get { return "WebServiceAuthentication"; }
} void OnEnter(Object source, EventArgs eventArgs)
{
HttpApplication app = (HttpApplication)source;
HttpContext context = app.Context;
Stream HttpStream = context.Request.InputStream; // Save the current position of stream.
long posStream = HttpStream.Position; // If the request contains an HTTP_SOAPACTION
// header, look at this message.HTTP_SOAPACTION
if (context.Request.ServerVariables["HTTP_SOAPACTION"] == null)
return; // Load the body of the HTTP message
// into an XML document.
XmlDocument dom = new XmlDocument();
string soapUser;
string soapPassword; try
{
dom.Load(HttpStream); // Reset the stream position.
HttpStream.Position = posStream; // Bind to the Authentication header.
soapUser =
dom.GetElementsByTagName("User").Item().InnerText;
soapPassword =
dom.GetElementsByTagName("Password").Item().InnerText;
}
catch (Exception e)
{
// Reset the position of stream.
HttpStream.Position = posStream; // Throw a SOAP exception.
XmlQualifiedName name = new
XmlQualifiedName("Load");
SoapException soapException = new SoapException(
"SOAP请求没有包含必须的身份识别信息", name, e);
throw soapException;
}
// 触发全局事件
OnAuthenticate(new WebServiceAuthenticationEvent
(context, soapUser, soapPassword));
Result.OnEndValid();
return;
}
void OnCheckError(Object sender, EventArgs e)
{
if (Result.BrokenRules.Count == )
{
return;
}
else
{
HttpApplication app = HttpContext.Current.ApplicationInstance;
app.CompleteRequest();
app.Context.Response.Write(Result.Error);
}
}
}

Authenticate事件是一个静态的变量,这样我们可以在程序的外部来订阅和取消订阅事件(非静态的public 事件在外部也是不能进行订阅和取消订阅事件的,这也是事件和委托的一个区别之一)

下面是我们的事件参数以及委托

 1 public delegate void WebServiceAuthenticationEventHandler(Object sender, WebServiceAuthenticationEvent e);
2
3 /// <summary>
4 /// 封装的事件参数
5 /// </summary>
6 public class WebServiceAuthenticationEvent : EventArgs
7 {
8 private IPrincipal _IPrincipalUser;
9 private HttpContext _Context;
10 private string _User;
11 private string _Password;
12
13 public WebServiceAuthenticationEvent(HttpContext context)
14 {
15 _Context = context;
16 }
17
18 public WebServiceAuthenticationEvent(HttpContext context,
19 string user, string password)
20 {
21 _Context = context;
22 _User = user;
23 _Password = password;
24 }
25 public HttpContext Context
26 {
27 get { return _Context; }
28 }
29 public IPrincipal Principal
30 {
31 get { return _IPrincipalUser; }
32 set { _IPrincipalUser = value; }
33 }
34 public void Authenticate()
35 {
36 GenericIdentity i = new GenericIdentity(User);
37 this.Principal = new GenericPrincipal(i, new String[0]);
38 }
39 public void Authenticate(string[] roles)
40 {
41 GenericIdentity i = new GenericIdentity(User);
42 this.Principal = new GenericPrincipal(i, roles);
43 }
44 public string User
45 {
46 get { return _User; }
47 set { _User = value; }
48 }
49 public string Password
50 {
51 get { return _Password; }
52 set { _Password = value; }
53 }
54 public bool HasCredentials
55 {
56 get
57 {
58 if ((_User == null) || (_Password == null))
59 return false;
60 return true;
61 }
62 }
63 }

  

我们在Global.asax的Application_Start方法里面把前面介绍的静态方法ServiceCredential.CheckUser订阅到我们Authenticate事件上,前面提到的增加和删除多种认证方式就是通过这种方法实现的.

  protected void Application_Start(object sender, EventArgs e)
{
WebServiceAuthenticationModule.Authenticate += ServiceCredential.CheckUser;
}

我们在ServiceCredential.ValideUser方法设置了返回false,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证 运行上面讲解SoapHeader的那段代码,你会发现我们的认证已经有效了.

webservice安全性之 SoapHeader自定义身份验证的更多相关文章

  1. WebService基于soapheader的身份验证

    用WebService开发接口十分方便.但接口提供的数据不应是对所有人可见的,我们来利用SoapHeader写一个简单的身份验证Demo 目录 创建WebService项目(带SoapHeader) ...

  2. WCF身份验证三:自定义身份验证之<MessageHeader>

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

  3. WCF身份验证二:基于消息安全模式的自定义身份验证

    使用X509证书进行身份验证应该说是WCF安全模型中最”正常”的做法, 因为WCF强制要求使用证书加密身份数据, 离开了证书, 所有的身份验证机制拒绝工作, WCF支持的身份验证机制也相当复杂, 这里 ...

  4. window10家庭版解决IIS中万维网服务的安全性中无Windows身份验证

    首先在左下角输入cmd搜索->命令提示符->以管理员身份运行->然后复制下面一段命令: dism /online /norestart /add-package:%SystemRoo ...

  5. asp.net mvc 自定义身份验证

    1.定义身份实体对象 /// <summary> /// 网站用户实体对象 /// </summary> public class DDTPrincipal : IPrinci ...

  6. asp.net webapi 自定义身份验证

    /// <summary> /// 验证 /// </summary> /// Account API账号 /// TimeStamp 请求时间 /// Sign 所有请求参数 ...

  7. asp.net mvc 自定义身份验证 2

    控制成员角色 [Authorize(Rroles="Administator,SuperAdmin")] public class StoreManagerController:C ...

  8. WebService安全性的几种实现方法【身份识别】

     转:http://blog.csdn.net/yongping8204/article/details/8619577 WebService安全性的几种实现方法[身份识别] 标签: webservi ...

  9. ASP.NET中WebService的两种身份验证方法

    一.通过SOAP Header身份验证 此方法是通过设置SOAP Header信息来验证身份,主要通过以下几步: 1.在服务端实现一个SOAP Header类 public class Credent ...

随机推荐

  1. 101、使用ContentProvider在应用间传递数据

    [ContentWriter] package com.jikexueyuan.contentwriter; import android.content.ContentProvider; impor ...

  2. [Flex] ButtonBar系列——简单布局

    <?xml version="1.0" encoding="utf-8"?> <!--通过layout属性,设置ButtonBar布局--&g ...

  3. CodeForces 604C 【思维水题】`

    题意: 给你01字符串的长度再给你一个串. 然后你可以在这个串中选择一个起点和一个终点使得这个连续区间内所有的位取反. 求: 经过处理后最多会得到多少次01变换. 例如:0101是4次,0001是2次 ...

  4. Android--使用Notification在通知栏显示消息

    在一个Activity中点击按钮,产生一个通知栏消息通知. package cn.luxh.mynotice; import android.os.Bundle; import android.uti ...

  5. Flex 医疗行程图

    ================================================ 病案的质量控制: 1.医生自检,主任检测,病案室检测达到三级检测 2.人工检测,自动检测 3.抽检(采 ...

  6. php分享表单提交到本页的实例

    我们在做表单提交时,一般都要设置表单的action属性,改属性用于指定表单提交到服务器上的哪个页面进行处理,但为空时,表示提交到本页进行处理,即提交给自己.本文章向大家分享表单提交给本页的实例. 实例 ...

  7. 一名合格QA的基本素养

    测试不是无脑的重复劳动.测试与开发一样,先用脑,再动手. 拒绝搬砖,关注技术: 把握需求,极致体验: 把控进度,高效沟通:   测试技术 如果你只会加班,行万里路,也只是个邮差 将程序测"好 ...

  8. 浅析JNI函数的注册过程

    我们在java中调用Native code的时候,一般是通过JNI来实现的,我们只需要在java类中加载本地.so库文件,并声明native方法,然后在需要调用的地方调用即可,至于java中nativ ...

  9. 简单的as3操作xml

    package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import ...

  10. org.springframework.core.NestedIOException

    今天遇到的一个小异常,报错信息如下: 2013-11-13 10:00:32 org.apache.catalina.core.StandardContext listenerStart严重: Exc ...