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 使用步骤: 下面展示一段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写一个处理模块,那么它的原理是什么呢?具体进行了哪些操作呢?我们的思路如下:
下面来看看我们的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) 我们在ServiceCredential.ValideUser方法设置了返回true,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |