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的代码,多余的方法将会在后面用到 客户端
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
当我们拥有很多个类的时候,要添加一个或者删除一个验证方式(假设需要进行多种认证)是非常麻烦的,我们不可能跑到每个方法里面去加一个方法调用,这是灾难性的工作,当然我们也可以用AOP来实现,Aop的话需要额外增加很多代码或者直接引入第三方来做,但是我们可不可以有更简便的方法呢?
?
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( " 验证错误 " , " 不能确认您的身份,请检查用户名和密码 " ); ??????????? } ??????? } ??? } OK,答案就是使用HttpModule,我们集成IHttpModule写一个处理模块,那么它的原理是什么呢?具体进行了哪些操作呢?我们的思路如下:
下面来看看我们的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) 我们在ServiceCredential.ValideUser方法设置了返回false,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证 很晚了,洗洗睡了,各位有什么好的想法可以留言,本人技术有限,权当抛砖引玉!!! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |