:::: 菜单 ::::

安全沙箱问题#2123

第一份安全沙箱的笔记。
因为安全沙箱困扰了不少人,所以是老生常谈的问题。
今天下午我遇到了2123错误。

案发现场

某个列表flash页面需要支持gravatar的头像
(gravatar的跨域策略文件位于http://www.gravatar.com/avatar/crossdomain.xml)
在加载他们提供的图片头像时我遇到了安全沙箱冲突,错误信息是:

SecurityError: Error #2123: 安全沙箱冲突:Loader.content:http://www.**********/lib.swf 不能访问 http://www.gravatar.com/avatar/3b3be63a4c2a439b013787721dfce802.jpg?s=26&d=monsterid。未被授权访问任何策略文件。
at flash.display::Loader/get content()
at org.mousebomb.srcloader::SwfLoader/onLoadComplete()

一开始我以为是要Crossdomain文件的,我加上了Security.loadPolicyFile(“http://www.gravatar.com/avatar/crossdomain.xml”); 尝试,无效。
其实并不需要的——我只是要发布到网站后跨域读取并显示图片,这在远程网络域中,是直接允许以只读方式访问视听媒体内容的

罪魁祸首

后来单独写了一个文件,用Loader测试了一下可以正常读取并显示图片的。
这样想起来原来导致安全错误的原因在于我所使用的资源加载器,资源池的最终工作单位中Loader是每次加载完成一个就把此视觉对象抛出,然后unload以便再次接受新任务。
片段代码:

  1. _isFree = true;
  2.             var _loadedData : DisplayObject = _loader.content;
  3.             _loader.unload();
  4.             var outEvent : SrcloaderEvent = new SrcloaderEvent(SrcloaderEvent.COMPLETE, {key:_key, type:_type, data:_loadedData});
  5.             this.dispatchEvent(outEvent);

这样的抛出视觉对象(错误出现在_loader.content这句)被 Flashplayer看作为“跨域数据处理” ,违反了只读的许可,是不允许的。

解决方案

这部分直接换成Loader来加载显示就行了。
针对跨域视听媒体对象的显示与读取只能用Loader直接做容器。

[11.8补充]

根据我的理解,远程网络域的图像要想进行处理(draw之类),只要服务器上有跨域策略文件标明允许,且loaderContext读取了此策略文件就可以的,但事实上,还是无法操作。
也许是对安全策略还不够了解,上次的问题虽然解决了却没有深入研究。

今天群里有个兄台(pickgliss)为解决问题,提出这样的方式绕过Loader加载来的图片无法draw、无法操作BitmapData的问题:
先用URLLoader以二进制方式加载图片,然后用Loader.loadBytes加载为显示对象。
我在后面加上draw位图和smoothing来测试,果然可行!

注意:此方法适用于远程服务器上有跨域安全策略赋予权限,但依然无法操作显示对象。不适用于没有跨域安全策略、或者策略文件不允许的情况。

如何绕过安全错误例:

  1. package 
  2. {
  3.     import flash.display.Bitmap;
  4.     import flash.display.BitmapData;
  5.     import flash.display.DisplayObject;
  6.     import flash.display.Loader;
  7.     import flash.display.Sprite;
  8.     import flash.events.Event;
  9.     import flash.net.URLLoader;
  10.     import flash.net.URLLoaderDataFormat;
  11.     import flash.net.URLRequest;
  12.     import flash.utils.ByteArray;
  13.  
  14.     public class Test extends Sprite
  15.     {
  16.         public function Test()
  17.         {
  18.             var req : URLRequest = new URLRequest("http://uc.discuz.net/data/avatar/001/29/18/69_avatar_middle.jpg");
  19.             var loader : URLLoader = new URLLoader(req);
  20.             loader.dataFormat = URLLoaderDataFormat.BINARY;
  21.             loader.addEventListener(Event.COMPLETE, __complete);
  22.         }
  23.  
  24.         private function __complete(e : Event) : void
  25.         {
  26.             var data : ByteArray = e.target.data;
  27.             var loader : Loader = new Loader();
  28.             loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageDataComplete);
  29.             loader.loadBytes(data);
  30.            
  31.         }
  32.  
  33.         private function imageDataComplete(e : Event) : void
  34.         {
  35.             var dio : DisplayObject = e.target.content;
  36.             var bmp : Bitmap = new Bitmap(new BitmapData(dio.width, dio.height),"auto",true);
  37.             bmp.bitmapData.draw(dio);
  38.             bmp.x = 100;
  39.             bmp.y = 100;
  40.             bmp.width = 50;
  41.             bmp.height = 50;
  42.             addChild(bmp);
  43.         }
  44.     }
  45. }

延伸阅读


  1. 脑子出问题了,错看成冰箱才进来的,想看看啥叫安全冰箱。。。

  2. Pingback: 无法设置Loader的大小? : : 9RIA.Com 天地会博客聚合 Unknow Unknow

  3. Pingback: 写了个位图缓存优化渲染方案 : : 9RIA.Com 天地会博客聚合 Unknow Unknow