WebService的安全性讨论【身份识别】
来源:互联网 发布:app原型设计工具 mac 编辑:程序博客网 时间:2024/05/18 04:55
http://www.aspxcs.net/HTML/0942423489.html#
相信很多开发者都用过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代码
- 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(0).InnerText;
- soapPassword =
- dom.GetElementsByTagName("Password").Item(0).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 == 0)
- {
- return;
- }
- else
- {
- HttpApplication app = HttpContext.Current.ApplicationInstance;
- app.CompleteRequest();
- app.Context.Response.Write(Result.Error);
- }
- }
- }
Authenticate事件是一个静态的变量,这样我们可以在程序的外部来订阅和取消订阅事件(非静态的public 事件在外部也是不能进行订阅和取消订阅事件的,这也是事件和委托的一个区别之一)
下面是我们的事件参数以及委托
- public delegate void WebServiceAuthenticationEventHandler(Object sender, WebServiceAuthenticationEvent e);
- /// <summary>
- /// 封装的事件参数
- /// </summary>
- public class WebServiceAuthenticationEvent : EventArgs
- {
- private IPrincipal _IPrincipalUser;
- private HttpContext _Context;
- private string _User;
- private string _Password;
- public WebServiceAuthenticationEvent(HttpContext context)
- {
- _Context = context;
- }
- public WebServiceAuthenticationEvent(HttpContext context,
- string user, string password)
- {
- _Context = context;
- _User = user;
- _Password = password;
- }
- public HttpContext Context
- {
- get { return _Context; }
- }
- public IPrincipal Principal
- {
- get { return _IPrincipalUser; }
- set { _IPrincipalUser = value; }
- }
- public void Authenticate()
- {
- GenericIdentity i = new GenericIdentity(User);
- this.Principal = new GenericPrincipal(i, new String[0]);
- }
- public void Authenticate(string[] roles)
- {
- GenericIdentity i = new GenericIdentity(User);
- this.Principal = new GenericPrincipal(i, roles);
- }
- public string User
- {
- get { return _User; }
- set { _User = value; }
- }
- public string Password
- {
- get { return _Password; }
- set { _Password = value; }
- }
- public bool HasCredentials
- {
- get
- {
- if ((_User == null) || (_Password == null))
- return false;
- return true;
- }
- }
- }
我们在Global.asax的Application_Start方法里面把前面介绍的静态方法ServiceCredential.CheckUser订阅到我们Authenticate事件上,前面提到的增加和删除多种认证方式就是通过这种方法实现的.
- protected void Application_Start(object sender, EventArgs e)
- {
- WebServiceAuthenticationModule.Authenticate += ServiceCredential.CheckUser;
- }
我们在ServiceCredential.ValideUser方法设置了返回false,这是针对测试的一个配置,实际情况下我们可以和数据库结合起来写一个认证
运行上面讲解SoapHeader的那段代码,你会发现我们的认证已经有效了.关于文章中用到的Result类改天在用一篇文章记录一下,这是一个非常好的记录错误的方案.
- WebService的安全性讨论【身份识别】
- WebService的安全性讨论【身份识别】
- WebService安全性的几种实现方法【身份识别】
- WebService 安全性的讨论
- WebService 安全性的讨论
- ASP.NET工作进程的安全性身份
- WebService的讨论
- LINUX用户身份的识别
- 增强WebService安全性的方法
- 【讨论】malloc的可重入性和线程安全性
- 有关Google服务安全性的技术讨论
- 有关Google服务安全性的技术讨论
- VPN及其安全性问题的讨论
- webservice安全性
- 用SOAP处理WEBSERVICE的安全性
- 通过SoapHeader来增强webService 的安全性
- 通过SOAPHeader增强WebService的安全性
- 通过SoapHeader来增强webService 的安全性
- 非齐次线形差分方程的两种情况下通解的求法2
- -46 error:平台安全问题
- 设置虚拟机默认时区
- 让四大浏览器用上雅黑字体
- VSS不需要验证自动登录的问题
- WebService的安全性讨论【身份识别】
- 迅雷使用积分制的真正作用和目的 [揭密迅雷]
- Red Hat / CentOS Apache 2 FastCGI PHP Configuration
- Andorid模拟器上网
- JSF运行的6个阶段
- svn教程
- 在XP Professional sp3系统中使用IIS运行ASP应用
- 实现函数自己调用自己
- UBI文件系统