我有一个asp.net网站,为客户端Flash播放器(SWF)提供示例MP3文件。
这些文件可以通过大量的下载工具下载。
虽然只有注册会员可以访问高质量的mp3样本,但我的客户希望通过下载工具防止这些低质量的MP3文件下载。
所以我想到了这个解决方案:
我能够成功直到第6步。我无法将此字节数组转换为Flash可以播放的Sound对象。我对Flash上的结果数组和ASP.NET上的源数组进行了一点一点的比较。他们相等。
我对完全不同的方法持开放态度。但我无法使用Flash Media Server。我需要使用Flash as3和ASP.NET。
同样非常重要! .mp3必须下载/解密并异步播放(我不能成功)
答案 0 :(得分:3)
我同意Peter Elliot认为,身份验证可能是限制访问文件的最简单方法。但是,如果您仍然需要探索加密文件的路径,我想我会扩展Alex Vlad的答案。
为了能够流式传输音频文件,动态解密并异步播放,您需要做的是使用URLStream
类(docs)和Sound
类(docs)并保留部分下载内容的缓冲区。
一些伪代码说明:
class AsyncEncryptedSoundPlayer extends Sound {
var buffer:ByteArray;
var stream:URLStream;
var currSoundPosition:uint = 0;
public function AsyncEncryptedSoundPlayer(url:String) {
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataRequested);
}
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray;
stream.readBytes(tmpData, buffer.length, stream.bytesAvailable - buffer.length);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.writeBytes(decryptedData, buffer.length, decryptedData.length); // Add decrypted data to buffer
}
function onSampleDataRequested(e:ProgressEvent):void {
// Feed samples from the buffer to the Sound instance
// You may have to pause the audio to increase the buffer it the download speed isn't high enough
event.data.writeBytes(buffer, currSoundPosition, 2048);
currSoundPosition += 2048;
}
function decryptedData(data:ByteArray):void {
// Returns decrypted data
}
}
这显然是一个课程的粗略轮廓,但我希望它会指出你正确的方向。
答案 1 :(得分:2)
@walkietokyo,非常感谢我指出正确的方向。我成功地做了我想做的事。这里的关键字是loadCompressedDataFromByteArray
函数。
经过数十次试验和错误后,我发现loadCompressedDataFromByteArray
正在以不同的方式运作。
追加将转换为声音对象数据末尾的任何内容。
另一个问题:在调用loadCompressedDataFromByteArray
函数后,声音对象不会继续播放play
附加的部分。
所以我实现了一种双缓冲。我交替使用2个声音对象的地方。
我的最终(测试)版本如下所示。使用我使用的加密(混淆)方法(一个简单的XOR)没有我测试的下载管理器或抓取器或嗅探器能够播放Mp3。
Flash(客户端)方:
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.OutputProgressEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.net.URLStream;
import flash.utils.ByteArray;
import flashx.textLayout.formats.Float;
var buffer:ByteArray;
var stream:URLStream;
var bufferReadPosition:uint = 0;
var bufferWritePosition:uint = 0;
var url:String = "http://www.blablabla.com/MusicServer.aspx?" + (new Date());
buffer = new ByteArray();
stream = new URLStream();
stream.addEventListener(ProgressEvent.PROGRESS, onProgress);
stream.load(new URLRequest(url));
var s1:Sound = new Sound();
var s2:Sound = new Sound();
var channel1:SoundChannel;
var channel2:SoundChannel;
var pausePosition:int = 0;
var aSoundIsPlaying:Boolean = false;
var lastLoadedS1:Boolean = false;
var lastS1Length:int = 0;
var lastS2Length:int = 0;
function onProgress(e:ProgressEvent):void {
var tmpData:ByteArray = new ByteArray();
stream.readBytes(tmpData, 0, stream.bytesAvailable);
var decryptedData:ByteArray = decryptData(tmpData); // Decrypt loaded data
buffer.position = bufferWritePosition;
buffer.writeBytes(decryptedData, 0, decryptedData.length); // Add decrypted data to buffer
bufferWritePosition += decryptedData.length;
if(lastLoadedS1)
{
buffer.position = lastS2Length;
s2.loadCompressedDataFromByteArray(buffer, buffer.length - lastS2Length);
lastS2Length = buffer.length;
}
else
{
buffer.position = lastS1Length;
s1.loadCompressedDataFromByteArray(buffer, buffer.length - lastS1Length);
lastS1Length = buffer.length;
}
if(!aSoundIsPlaying)
{
DecidePlay();
}
}
function channel1Completed(e:Event):void
{
DecidePlay();
}
function channel2Completed(e:Event):void
{
DecidePlay();
}
function DecidePlay():void
{
aSoundIsPlaying = false;
if(lastLoadedS1)
{
channel1.stop();
if(s2.length - s1.length > 10000)
{
//At least a 10 second buffer
channel2 = s2.play(s1.length);
channel2.addEventListener(Event.SOUND_COMPLETE, channel2Completed);
lastLoadedS1 = false;
aSoundIsPlaying = true;
}
}
else
{
if(channel2 != null)
{
channel2.stop();
}
if(s1.length - s2.length > 10000)
{
//At least a 10 second buffer
channel1 = s1.play(s2.length);
channel1.addEventListener(Event.SOUND_COMPLETE, channel1Completed);
lastLoadedS1 = true;
aSoundIsPlaying = true;
}
}
}
function decryptData(data:ByteArray):ByteArray {
for(var i:int = 0;i<data.length;i++)
{
//Here put in your bitwise decryption code
}
return data;
}
ASP.NET服务器端(MusicServer.aspx):
protected void Page_Load(object sender, EventArgs e)
{
CopyStream(Mp3ToStream(Server.MapPath("blabla.mp3")), Response.OutputStream);
this.Response.AddHeader("Content-Disposition", "blabla.mp3");
this.Response.ContentType = "audio/mpeg";
this.Response.End();
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
for (int i = 0; i < read; i++)
{
//Here put in your bitwise encryption code
}
output.Write(buffer, 0, read);
}
}
public Stream Mp3ToStream(string filePath)
{
using (FileStream fileStream = File.OpenRead(filePath))
{
MemoryStream memStream = new MemoryStream();
memStream.SetLength(fileStream.Length);
fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
return memStream;
}
}
答案 2 :(得分:1)
加密从您的服务返回的数据可能更简单,而是验证请求,以便只有您的swf可以请求文件。
您可以使用与Amazon API相同的方式完成此任务:构建包含许多参数的请求,包括时间戳。将所有这些参数一起散列在HMAC中(HMAC-SHA256在as3crypto library中可用)以及嵌入在swf中的私钥。您的服务器端对此请求进行身份验证,确保哈希值有效且与时间戳足够接近。任何带有错误哈希的请求,或使用过去时间戳太远的请求(重放攻击)都会被拒绝。
这肯定不是完美的安全性。任何有足够动力的用户都可以反汇编你的swf并拔出你的auth密钥,或从他们的浏览器缓存中获取mp3。但话说回来,你要使用的任何机制都会遇到这些问题。这消除了必须加密和解密所有文件的开销,而不是将工作转移到请求生成阶段。
答案 3 :(得分:0)
Flash Sound
仅支持流式mp3播放,您只能通过直接链接播放mp3。但你可以用嵌入式mp3发送带有它的swf文件,这个swf可以像加密mp3一样加密。
用于嵌入和使用mp3的as3代码:
public class Sounds
{
[Embed(source="/../assets/sounds/sound1.mp3")]
private static const sound1:Class;
}
通过Loader
加载此swf后,您可以通过以下方式访问声音:
var domain:ApplicationDomain = ApplicationDomain.currentDomain; // <-- ApplicationDomain where you load sounds.swf
var soundClass:Class = domain.getDefinition("Sounds_sound1");
var sound:Sound = new soundClass();
sound.play();
请确保您至少执行以下操作之一:
sound1
)Sounds
)防止类名重叠。
不幸的是,这种方法不允许你播放播放声音,你必须加载整个swf,解密它,然后才能播放声音。
答案 4 :(得分:0)