翔如菲菲

其实天很蓝,阴云总会散;其实海不宽,此岸连彼岸.

导航

Silverlight跨域支持

 跨域支持

在学习各种不同的网络功能之前,有必要讨论一些有可能出现在Silverlight应用程序到某台服务器的网络调用中的问题。从一个Web站点域到另外一个站点域的调用(称为跨域调用),对需要从分布式数据源中检索数据的应用程序而言是常有的事。这一点在从多个站点和服务中检索数据的混搭(mash-up)应用程序中就更加明显了。如果使用过类似于Asynchronous JavaScript and XML(AJAX)的Web技术,那么就知道从客户端浏览器实施跨域调用并不总是那么简单。

AJAX使用了XmlHttpRequest对象,该对象要求所有的调用都必须回到最初提供支持AJAX的页面的服务器以开始执行。XmlHttpRequest对象不允许调用其他Internet域,这主要是因为各种不同的安全攻击(如跨域伪造等),均可以用于偷取用户的数据。正因为该限制,所以AJAX应用程序通常要调用位于初始服务器上的中间服务,而该服务再调用远程的服务以检索跨域数据。尽管这些技术在大量的网站中使用,但是该技术需要额外的工作,并且需要在交互中引入一个中间人(尽管它允许使用不同的缓存技术以提高应用程序所使用数据的可靠性)。

和AJAX不一样,Silverlight支持跨域调用,但是默认情况下只能调用相同的站点(有时称为初始站点(site of origin))。这就意味着,可以安全地从位于www.site.com的站点上的Silverlight客户端调用位于www.site.com/MyService站点上的服务,且不需要做太多的工作。但是默认情况下,Silverlight客户端不能调用位于www.site.com:9090/MyService上的服务,因为其端口不同。Silverlight执行以下的检测来查看服务器是否和Silverlight客户端处于同一个域中:

协议一样,

域名一样,

端口号一样。

如果完全可以控制客户端应用程序和服务器应用程序,那么一般不需要担心跨域调用问题。但是,当Silverlight客户端需要使用一个由诸如亚马逊和谷歌之类的提供商所提供的服务时,或者是某个位于和Silverlight应用程序同一域、但具有不同端口或使用不同协议的服务时,将遇到跨域问题。

也可以通过在Visual Studio中将一个新的Web服务项目添加到已有的Silverlight 2项目中,以模拟跨域调用的行为。任何试图从Silverlight客户端调用服务的企图,都将得到一个非常奇怪的出错信息"The remote server returned an unexpected response: (404) Not Found."。初看该错误,可以会认为服务 Reference没有正确设置,因此需要修改服务的URL。但是在大多数情况下,这不是该错误的原因。该错误是由Silverlight产生的,因为它认识到正在试图执行一个跨域调用。

只有在目标服务器根目录中有一个特定的XML跨域策略文件时,才能进行跨域调用。如果Silverlight没有检测到该文件,或者发起调用的域被拒绝访问,那么将产生该异常。Silverlight 2支持两种类型的跨域策略:Flash的crossdomain.xml文件和Silverlight的clientaccesspolicy.xml文件。当产生了跨域调用时,Silverlight首先检查在服务器上是否有cilentaccesspolicy.xml文件。如果没有该文件,它将检查是否有crossdomain.xml文件。下面我们仔细地看看这两类跨域策略文件。

1  Flash跨域策略文件

跨域策略文件首先是由Flash引入的。Flash允许集成来自多个站点和服务的数据。目前的许多流行Web站点上均在其根目录中包含一个名为crossdomain.xml的Flash跨域策略文件,以允许外部的Flash应用程序和该站点实施对话。Silverlight支持crossdomain.xml文件格式的一个子集。下面是所支持文件的一些例子:

<?xml version="1.0"?> 
<cross-domain-policy> 
<allow-http-request-headers-from domain="*" headers"*"/> 
</cross-domain-policy> 
<?xml version="1.0"?> 
<cross-domain-policy> 
<allow-access-from domain="*" /> 
</cross-domain-policy> 

第一个例子允许任意头从任意站点发送到服务器,这一点在必须允许发送诸如SOAPAction的头(使用Web服务)时非常有用。特定的头值可以添加到headers属性中,这将比使用*更加安全。第二个例子允许从使用RESTful调用的域访问服务器。Silverlight仅仅支持一个值为*的domain属性。

关于crossdomain.xml文件的其他信息,可以查看http://www.adobe.com/devnet/ articles/ crossdomain_policy_file_spec.html。

如果站点承载了Flash客户端可以访问的服务,那么将希望在该站点的根目录中添加该crossdomain.xml文件。如果仅有Silverlight客户端可以访问该服务,那么可以像下面所讨论的那样,添加一个名为clientaccesspolicy.xml的文件到该站点的根目录。

可能会遇到这样的crossdomain.xml文件,该文件在顶部定义了一个文档类型定义(Document Type Definition,DTD),并且引用了www.macromedia.comwww.adobe.com。Silverlight 2不会考虑该DTD,因为在crossdomain.xml文件中会有不同的版本。

2  Silverlight跨域策略文件

Flash跨域访问策略文件格式可以很好地通过域来限制对服务器的访问,但是它不允许对服务器的特定资源实施访问控制。在目前"安全第一"的情况下,更好地控制哪种资源可以访问将是众所期待的功能。不管怎么样,如果调用者不能访问服务器上的所有文件夹,那么为什么首先为调用者赋予这么高的访问权限呢?

为了减少跨域调用者所遇到的问题,微软公司发布Silverlight特有的跨域策略文件,名为clientaccesspolicy.xml。该文件为哪些域可以使用跨域调用来调用服务器、该域中的哪些资源允许访问以及允许使用哪些HTTP请求头,提供了额外的控制。下面是一个clientaccesspolicy.xml文件的例子:

<?xml version="1.0" encoding="utf-8"?> 
<access-policy> 
<cross-domain-access> 
<policy> 
<allow-from http-request-header="*"> 
<domain uri="*"/> 
</allow-from> 
<grant-to> 
<resource path="/Services" include-subpaths="true"/> 
</grant-to> 
</policy> 
</cross-domain-access> 
</access-policy>

该文件允许任意站点的跨域调用访问位于服务器根目录下Services文件夹中的资源。

    PS:如果是<resource path="/" include-subpaths="true"/> 则表示:
该文件允许任意站点的跨域调用访问位于服务器根目录中的资源

allow-from元素提供了定义哪些域可以访问服务的一种方式,这一点非常类似于Flash的crossdomain.xml文件。但是,Silverlight的策略文件更深入了一步,该文件使用grant-to元素来允许服务器控制哪些资源可以访问,以及通过使用http-request-header属性来控制哪种HTTP请求头可以传递。http-request-header属性接收通配符(*)字符以表示所有HTTP请求头均可以传递。关于当前不可用头的更多细节,可以在Silverlight SDK中找到,也可以在http://msdn.microsoft.com上找到。通过为http-request-header属性提供一个由逗号隔开的列表,可以在http-request-header中定义多个请求头。

当不同域可以访问不同资时,可以添加多个policy元素:

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  
<cross-domain-access>
    
<policy>
      
<allow-from http-request-headers="*">
        
<domain uri="*"/>
      
</allow-from>
      
<grant-to>
        
<resource path="/Services" include-subpaths="false"/>
      
</grant-to>
    
</policy>
    
<policy>
      
<allow-from http-request-headers="*">
        
<domain uri="*.domainName.com"/>
      
</allow-from>
      
<grant-to>
        
<resource path="/SpecialServices" include-subpaths="true"/>
      
</grant-to>
    
</policy>
  
</cross-domain-access>
</access-policy>
该跨域策略文件允许domainName.com域访问SpecialServices目录以及该目录下的子路径。当Silverlight客户端可以访问服务器根目录下的所有内容时,resource元素的path属性可以赋予/值,并且为include-subpaths属性赋予值true。

当某个服务器的Flash程序或者Silverlight客户端可以访问所有资源时,将一个简单的Flash crosspolicy.xml文件放置在服务器上就可以完成该任务。当需要为Silverlight客户端锁定特定的资源时,需要将一个clientaccesspolicy.xml文件放置该根目录下。如果Flash客户端不会调用服务器,那么推荐使用clientaccesspolicy.xml文件,因为该类文件可以限制资源和HTTP请求头,所以该类文件可以提供最好的安全性。

本文摘自:《Silverlight 2 & ASP.NET高级编程》 

posted on 2011-08-09 09:51  翔如飞飞  阅读(296)  评论(0编辑  收藏  举报