WebService的安全性讨论【身份识别】

相信很多开发者都用过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的代码,多余的方法将会在后面用到

客户端

View Code
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();            
        }
    }

服务器端

View Code
   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代码

 

View Code
  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 事件在外部也是不能进行订阅和取消订阅事件的,这也是事件和委托的一个区别之一)

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

 

View Code
 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方法设置了返回true,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证
运行上面讲解SoapHeader的那段代码,你会发现我们的认证已经有效了.关于文章中用到的Result类改天在用一篇文章记录一下,这是一个非常好的记录错误的方案.

很晚了,洗洗睡了,各位有什么好的想法可以留言,本人技术有限,权当抛砖引玉!!!

 

转载于:https://www.cnblogs.com/Creator/archive/2011/03/23/1992019.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值