您的位置:首页 > 其它

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

2017-05-14 05:17 447 查看
转:http://blog.csdn.net/yongping8204/article/details/8619577

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

标签: webservice 安全认证
2013-02-27 21:51 7778人阅读 评论(0) 收藏 举报


分类:
WEB技术(C#)(22)


相信很多开发者都用过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写一个处理模块,那么它的原理是什么呢?具体进行了哪些操作呢?我们的思路如下:

HTTP Module 分析 HTTP 消息以检查它们是不是 SOAP 消息。

如果 HTTP Module 检测到 SOAP 消息,它会读取 SOAP 标头。

如果 SOAP 消息的 SOAP 标头中有身份验证凭据,HTTP Module 将引发一个自定义 global.asax 事件。

下面来看看我们的Module代码

1  public class WebServiceAuthenticationModule : IHttpModule
2     {
3         private static WebServiceAuthenticationEventHandler
4                       _eventHandler = null;
5         /// <summary>
6         /// 验证事件.绑定到此事件可进行对用户身份的识别
7         /// </summary>
8         public static event WebServiceAuthenticationEventHandler Authenticate
9         {
10             add { _eventHandler  = value; }
11             remove { _eventHandler -= value; }
12         }
13         public Result Result = new Result();
14
15         public void Dispose()
16         {
17         }
18         public void Init(HttpApplication app)
19         {
20             app.AuthenticateRequest  = new
21                        EventHandler(this.OnEnter);
22             Result.EndValid  = new
23                 EventHandler(this.OnCheckError);
24         }
25
26         /// <summary>
27         /// 验证用户身份
28         /// </summary>
29         /// <param name="e"></param>
30         private void OnAuthenticate(WebServiceAuthenticationEvent e)
31         {
32             if (_eventHandler == null)
33                 return;
34
35             _eventHandler(this, e);
36             if (e.User != null)
37                 e.Context.User = e.Principal;
38         }
39
40         public string ModuleName
41         {
42             get { return "WebServiceAuthentication"; }
43         }
44
45         void OnEnter(Object source, EventArgs eventArgs)
46         {
47             HttpApplication app = (HttpApplication)source;
48             HttpContext context = app.Context;
49             Stream HttpStream = context.Request.InputStream;
50
51             // Save the current position of stream.
52             long posStream = HttpStream.Position;
53
54             // If the request contains an HTTP_SOAPACTION
55             // header, look at this message.HTTP_SOAPACTION
56             if (context.Request.ServerVariables["HTTP_SOAPACTION"] == null)
57                 return;
58
59             // Load the body of the HTTP message
60             // into an XML document.
61             XmlDocument dom = new XmlDocument();
62             string soapUser;
63             string soapPassword;
64
65             try
66             {
67                 dom.Load(HttpStream);
68
69                 // Reset the stream position.
70                 HttpStream.Position = posStream;
71
72                 // Bind to the Authentication header.
73                 soapUser =
74                     dom.GetElementsByTagName("User").Item(0).InnerText;
75                 soapPassword =
76                     dom.GetElementsByTagName("Password").Item(0).InnerText;
77             }
78             catch (Exception e)
79             {
80                 // Reset the position of stream.
81                 HttpStream.Position = posStream;
82
83                 // Throw a SOAP exception.
84                 XmlQualifiedName name = new
85                              XmlQualifiedName("Load");
86                 SoapException soapException = new SoapException(
87                           "SOAP请求没有包含必须的身份识别信息", name, e);
88                 throw soapException;
89             }
90             // 触发全局事件
91             OnAuthenticate(new WebServiceAuthenticationEvent
92                          (context, soapUser, soapPassword));
93             Result.OnEndValid();
94             return;
95         }
96         void OnCheckError(Object sender, EventArgs e)
97         {
98             if (Result.BrokenRules.Count == 0)
99             {
100                 return;
101             }
102             else
103             {
104                 HttpApplication app = HttpContext.Current.ApplicationInstance;
105                 app.CompleteRequest();
106                 app.Context.Response.Write(Result.Error);
107             }
108         }
109     }


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的那段代码,你会发现我们的认证已经有效了.关于文章中用到的Result类改天在用一篇文章记录一下,这是一个非常好的记录错误的方案
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: