你的分享就是我们的动力 ---﹥

Silverlight 4的数字版权管理(DRM)

时间:2011-10-24 09:55来源:www.chengxuyuans.com 点击:

注意:本主题特定于 Silverlight 4。若要了解 Silverlight 3 中的 DRM,请参见数字版权管理 (Silverlight 3)。

在将数字版权管理 (DRM) 集成到 Silverlight 应用程序后,您可以针对各种方案更好地保护内容并 更安全地跨平台交付内容,包括流处理内容、渐进式下载内容、租赁内容和订阅。

DRM 方案

可以使用 DRM 来帮助您交付音频和视频内容,这样更安全且更好地保护内容不受未经授权的获取和再 分发。这种保护机制可以集成到各种业务方案中,包括:

联机方案:这些方案要求用户在播放媒体内容时处于联机状态:

实时流处理:实时流处理也称为“真正的流处理”,它直接将内容发送到计算机或设备,而不将文件 保存到硬盘。仅当广播时,实时流才可用。实时流处理的示例是 Internet 电视和广播。

渐进式下载:渐进式下载使得用户能够在媒体正处于下载时进行播放。从用户的角度来看,渐进式下 载与实时流处理之间的主要区别在于:渐进式下载的内容存储在用户的计算机或设备上(至少是临时存储 )。

脱机方案:这些方案允许用户在播放内容时处于脱机状态。这些方案的确要求在用户的计算机或设备 上安装脱机版 Silverlight 运行时,并且确实要求用户处于联机状态(至少应间歇性联机),以便最初 下载内容并重续订阅。

脱机下载文件(一次性购买):用户从 Internet 下载内容,然后使用脱机版 Silverlight 播放器播 放内容。例如,一个联机视频商店向客户收取费用让其下载视频文件,用户可以在需要时在脱机版 Silverlight 播放器中播放此文件。DRM 软件可以将视频文件的再分发限制为一台或更多台设备(请看本 文后面的域)。

租赁:您可以在 DRM 许可证中指定时间限制,以限制内容的播放。例如,某个联机视频商店可能提供 其视频用于出租。一旦购买了租赁内容并下载了许可证,许可证就会在许可证签发之日起的 30 天之后或 首次播放的 24 小时之后过期(以先到者为准)。

订阅:使客户能够根据订阅模型播放内容。例如,联机视频商店的客户支付每月费用,可联机观看最 多 100 个小时的电视内容和下载最多 20 集电视剧。为了续订其订阅,客户需要支付每月费用,并每月 至少需要连接到此服务一次,因为订阅许可证每 45 天就会过期。

注意 在 FAT32 上安装的 Windows XP 操作系统不支持 Silverlight DRM 方案。

Silverlight DRM 联机方案

以下各节说明如何启用联机 Silverlight DRM 方案。此处介绍的许多概念也适用于脱机方案;但脱机 方案(如租赁和订阅)将在稍后的 Silverlight DRM 脱机方案中介绍。

本节考察在 Silverlight 中播放 DRM 内容所需的最低限度的组件。这些组件同时适用于联机方案和 脱机方案;但是,某些方案要求提供附加组件,后续章节中将介绍它们。

Silverlight DRM 联机概念性概述

下图汇总了 Silverlight 播放 DRM 内容所需的过程以及推动这些过程完成所需的服务器/客户端交互 。之后将更详细地讨论其中的每个步骤。

1.Silverlight 客户端访问内容

最终用户尝试在 Silverlight 应用程序中播放某些存储在分发服务器上的受 DRM 保护的内容(分发 服务器通常为 Web 服务器,用来分发您的内容)。Silverlight 客户端下载内容(如果是流,则为部分 内容)和标头。

2.对每个客户端进行个性化处理吗?

在 Silverlight 请求许可证来解密内容之前,Silverlight 必须先确定最终用户的计算机上是否安装 了适当的 DRM 软件。这种软件称为个性化组件,是在播放任何受保护的内容之前所需的 DRM 客户端组件 。个性化组件软件使客户端计算机可以请求和使用 DRM 许可证,并保护在解密过程中用到的敏感数据。

如果客户端上还没有适当的个性化组件软件,客户端将向 Microsoft Individualization Service 请 求该组件。获取个性化的组件软件的过程称为"个性化"。Silverlight 通过将信息发送到 Microsoft Individualization Service 对用户计算机进行个性化处理(注意最终用户可以阻止发送此信息;请参见 本主题后面的错误处理。一旦安装了有效的个性化组件,在 Microsoft 推出新版本的个性化组件之前, 客户端不需要再次进行个性化处理。

3.Silverlight 请求许可证

一旦客户端上存在有效的个性化组件软件,就可开始播放 DRM 了。现在,在访问带有 DRM 内容的页 面时,Silverlight 客户端将联系 PlayReady 许可证服务器以获取许可证(许可证服务器由您或您的服 务提供商控制)。如果许可证服务器批准该请求,则颁发许可证,客户端将使用该许可证来解密特定的媒 体文件。之后,就可以播放内容了。

PlayReady 与 WMDRM 的对比

Silverlight 客户端可以使用两种形式的 DRM 加密/解密:传统的 Windows Media 数字权限管理 10 (WMDRM 10) 和较新的带有 AES 加密的 PlayReady。这使得使用 WMDRM 10 SDK 加密的现有内容可以同时 在 Silverlight 和其他支持 DRM 的 Windows Media 播放软件(如 Windows Media Player)中播放,并 使得仅限在 Silverlight 中播放的媒体可提供更高程度的安全性。

说明:

尽管 Silverlight 可以播放 PlayReady 和 WMDRM 加密的内容,但不支持这些技术的整个生态系统。 此外,为了在 Silverlight 中播放 WMDRM 加密的内容,您仍然需要至少一个 PlayReady 服务器(请参 见上面的关系图)。

使用 Silverlight DRM 时的限制

即使您只打算使用 WMDRM 加密内容,也要注意您将需要至少一个 PlayReady 许可证服务器才能将许 可证分发到 Silverlight 客户端。同时还要注意 Silverlight DRM 当前仅支持 PlayReady 的部分功能 。下面列出了使用 Silverlight DRM 时的重要限制:

Silverlight 并非支持 PlayReady 所支持的全部文件类型。Silverlight DRM 只支持 Windows Media 音频 (WMA)、Windows Media 视频 (WMV) 以及针对 PlayReady 的 PYA/PYV 文件。

PlayReady 许可证可以指定精确定义在何种条件下可以何种方式使用内容的权限和限制;但是,使用 Silverlight DRM 时唯一可用的许可证类型是只可播放一次的非永久性许可证。

没有许可证缓存。

使用 PlayReady 加密与 WMDRM 加密的注意事项

在设置用于将 DRM 与 Silverlight 结合起来使用的结构时,请谨记一些注意事项:

在对内容进行流处理时,您是从实时源中实时地进行编码和流处理,还是按需对预先加密的文件进行 流处理?

您的客户使用 Silverlight 播放内容还是也使用 Windows Media Player?

您有希望用来为 Silverlight 客户提供服务的大型 WMDRM 加密内容库(使用 WMRM SDK 加密)吗? 或者您能使用 PlayReady 加密您的全部内容吗?

无论这些注意事项的内容如何,如果您希望向 Silverlight 提供 DRM 内容,都需要购买至少一个 PlayReady 许可证服务器;不过,这些问题的回答会决定您能够仅使用 PlayReady 加密完成任务,还是 在整个 DRM 解决方案中需要额外处理 WMDRM 加密的内容。

流内容:当前,PlayReady Server SDK 只支持文件加密,因而不支持实时加密(在实时加密中实时编 码实时源中的流内容);在这种情况下必须使用 WMDRM。请参见本主题后面的在 Silverlight 中播放 WMDRM 内容,获取将 WMDRM 与 Silverlight 集成的可能的解决方案。请注意,WMDRM 和 PlayReady 都 支持预先加密的内容流。

客户端播放器:如果您的客户只使用 Silverlight 播放 DRM,则您可以使用 PlayReady 加密所有内 容;但是,如果某些客户还使用 Windows Media Player (WMP),则您也需要使用 WMDRM 来加密内容。

您的内容库:无论您是否只在 Silverlight 中播放内容,如果出于任何原因您都不希望使用 PlayReady 重新加密受保护的内容,都需要创建考虑 WMDRM 加密内容的 DRM 解决方案。

说明:

Silverlight 不支持带有脚本流(脚本流通过隐藏式字幕等流提供文本)的 WMDRM 内容。如果使用脚 本流播放 WMDRM 内容,音频和视频将能正常播放,但脚本流将被忽略。

在 Silverlight 中播放 WMDRM 内容

下图从概念上说明了如何将服务于非 Silverlight(旧式 WMDRM)客户端的现有 WMDRM 加密内容库与 Silverlight 客户端一起使用:

为了包括该库,您需要在 Silverlight 客户端上包括某些逻辑,以便将许可证请求路由到适当的 PlayReady 许可证服务器。

在 Silverlight 中集成 DRM

将 DRM 集成到 Silverlight 中需要许多步骤:

建立必需的服务器基础结构以提供受 DRM 保护的内容。

使用 MediaElement 从 Silverlight 应用程序指向这些受保护的内容。

处理预期错误(例如,当最终用户不允许 DRM 内容时)。

如果需要,基于 LicenseAcquirer 类创建一个子类以获得自定义业务逻辑。

建立服务器基础结构

为了使用 DRM,您必须先加密要保护的内容并使其可从分发服务器提供给客户端。可以使用加密软件 执行此操作。如上所述,您有两个加密选择:

WMDRM 10 SDK。

PlayReady Server SDK。

加密和打包内容时,要指定许可证获取 URL (LAURL)。在将许可证质询发送到许可证服务器之前,您 有机会在 Silverlight 应用程序中重写该值 – 如果您有一个 WMDRM 加密内容库并希望将该内容同时提 供给 Silverlight 和 Windows Media Player 客户端,那么这个方法尤其有用。

从 Silverlight 应用程序指向 DRM 内容

如果只使用 PlayReady 服务器来加密编码的内容,则可以仅使用 MediaElement 的 Source 属性来指 向该内容。

XAML

<MediaElement x:Name="myMediaElement" Source="myProtectedVideo.wmv" />

这是因为使用 PlayReady SDK 加密的内容在其内容头中包含授权服务器的 URI 位置。但是,如果您 使用 WMRM SDK 来加密内容,则授权服务器的位置将不会包含在标头中,因此您需要指定此 URI。为此, 请使用 LicenseServerUriOverride 属性为 MediaElement 指定用于查找许可证的 URI:

检测 DRM 状态

可以使用 MediaElementState 枚举来检测 MediaElement 所处的状态 – 具体而言即 MediaElement 当前正在对 Silverlight 客户端进行个性化处理还是获取许可证。检测这些状态的一个原因是,您可以 为用户提供有关 MediaElement 准备播放内容时所发生的情况的反馈。例如,当正在进行个性化时或者正 在使用 TextBlock 请求许可证时可以通知用户,如下面的示例所示。

错误处理

用户在 Silverlight 中使用 DRM 时可能会遇到许多错误。开发人员应当预计到这些错误并显示适当 的消息,以便用户能够了解到没有按预期的方式进行播放的原因,这一点很重要。

用户可能遇到的一个特定于 DRM 的错误发生在如下情况:用户已经通过在 Silverlight 的"配置"对 话框中取消选中下图所示的复选框来选择不允许 DRM。

这实际上不允许用户的客户端计算机向 Microsoft Individualization Server 请求个性化处理。

如果 MediaElement 尝试在这种情况下播放 DRM 内容,则 MediaElement 将引发一个新的 MediaFailed 事件以及如下错误:6008 DRM_E_INDIVIDUALIZATION_DISALLOWED。

您可能希望侦听此错误并在它发生时引发您自己的自定义消息。

下面是与 Silverlight DRM 相关的错误列表。请注意,错误号是 6000 和 6008 之间的连续数字。

6000 DRM_E_UNABLE_TO_PLAY_PROTECTED_CONTENT MediaElement 未能播放受 DRM 保护的内容。
6001 DRM_E_INDIV_DOWNLOAD_FAILURE 该个性化组件软件未能下载到用户计算机。当 MediaElement 处在 IndividualizingMediaElementState 时将出现此错误。出现此错误的一个可能原因是,Silverlight 客 户端无法连接 Microsoft Individualization Server。
6002 DRM_E_LICENSE_ACQUISITION_FAILURE 许可证获取失败。当 MediaElement 处在 AcquiringLicenseMediaElementState 时将出现此 错误。出现此错误的一个可能原因是,Silverlight 客户端无法连接到许可证服务器。
6003 DRM_E_INDIV_INSTALL_FAILURE 未能安装个性化组件软件。
6004 DRM_E_SILVERLIGHT_CLIENT_REVOKED Silverlight 客户端上的个性化软件已过期并需要更新。
6005 DRM_E_INVALID_PROTECTED_FILE_HEADER 处理文件头时失败。例如,文件头的格式可能不正确。
6006 DRM_E_LICENSE_PROCESSING_FAILURE 在 Silverlight 客户端上处理许可证失败。当 MediaElement 处在 AcquiringLicense MediaElementState 时将出现此错误。
6007 DRM_E_LICENSE_ACQUISITION_SERVICE_SPECIFIC PlayReady 许可证服务器允许服务器开发人员返回一个特定于服务的错误。这可能是像"您需 要付账单了"、"抱歉,此服务不可用"、"您已用完您的月流量"之类的消息。从许可证服务器返回的 SOAP 异常在服务器添加的 CustomData 字段中具有额外数据。您需要在 Silverlight 应用程序中编写应用程 序逻辑来解释这一情况。这些响应主要在实现自定义许可证获取时使用(请参见本主题后面的添加自定义 逻辑)。
6008 DRM_E_INDIVIDUALIZATION_DISALLOWED 用户在他们的 Silverlight 配置设置中禁用了 DRM(请参见本节以上内容)。

?μ?÷£o

è?1??úòaêμ???ú×??oμ?×??¨ò?Dí?é?¤??è?£?±?D???±êí· msprdrm_server_redirect_compat:false oí msprdrm_server_exception_compat:false ìí?óμ??úμ? HTTP Web ???ó?D£?·??ò′í?óoí???¨?ò???¢???T·¨ ?y3£1¤×÷?£??2?????ò??ú?Dμ?′ú??ê?ày?£

ìí?ó×??¨ò????-

MediaElement ê1ó? LicenseAcquirer ààà′′|àí???? DRM ?ó?ü?úèY?ò PlayReady Dí?é?¤·t???÷??è? Dí?é?¤μ?1y3ì?£?ú?éò??ùóú LicenseAcquirer àà′′?¨ò???×óàà2¢ìí?ó×??¨ò????-£?àyè????ú×??oμ?×??¨ ò?éí·Y?é?¤·?°?ìí?óμ?Dí?é?¤???ó?£

????μ?ê?ày?Yê?è?o???D′ LicenseAcquirer àࣨ???a"ManualLicenseAcquirer"£?2¢è? MediaElement ê1ó??üà′??è?Dí?é?¤?£

XAML

<StackPanel??x:Name="LayoutRoot"??Background="Gray"?? Orientation="Vertical">
???? <MediaElement??x:Name="myME"??Height="100"/>
</StackPanel>

VB

Public??Class??Page
???? Inherits??UserControl

???? Public??Sub??New()
???????? MyBase.New
???????? InitializeComponent
???????? AddHandler??Loaded,??AddressOf??Me.Page_Loader
???? End??Sub

???? Private??Sub??Page_Loaded(ByVal??sender??As??Object,??ByVal??e??As??RoutedEventArgs)
???????? '??Test??a??full??fledged??manual??acquirer
???????? '??Set??the??LicenseAcquirer??of??the??MediaElement??to??the??custom??License?? Aquirer
???????? '??defined??in??this??sample.
???????? myME.LicenseAcquirer??=??New??ManualLicenseAcquirer(myME.Name)
???????? '??Set??the??License??URI??to??proper??License??Server??address.
???????? myME.LicenseAcquirer.LicenseServerUriOverride??=??New??Uri ("http://contoso.com/myLicenseServer.asmx",??UriKind.Absolute)
???????? AddHandler??myME.MediaFailed,??AddressOf??Me.myME_MediaFailer
???????? '??Set??the??source??of??the??MediaElement??to??the??URL??of??the??media?? encrypted??with??WMDRM.
???????? myME.Source??=??New??Uri("http:,??contoso.com/wmdrm_url.wmv",?? UriKind.Absolute);)
???? End??Sub

???? Private??Sub??myME_MediaFailed(ByVal??sender??As??Object,??ByVal??e??As?? ExceptionRoutedEventArgs)
???????? Dim??errorMessage??As??String??=??""
???????? If??e.ErrorException.ToString.Contains("??6001??")??Then
???????????? errorMessage??=??"The??individualization??component??software??failed??to"?? &??_
???????????????????????????? "??download??to??the??user's??computer.??This??error??would"??&??_
???????????????????????????? "??come??up??when??the??MediaElement??is??in??the??Individualizing"??&??_
???????????????????????????? "??MediaElementState.??One??possible??reason??for??this??error??is"??&??_
???????????????????????????? "??that??the??Silverlight??client??cannot??connect??the??Microsoft"??&??_
???????????????????????????? "??Individualization??Server."
???????? ElseIf??e.ErrorException.ToString.Contains("??6004??")??Then
???????????? errorMessage??=??"The??individualization??software??on??the??Silverlight?? client??is"??&??_
???????????????????????????? "??out??of??date??and??needs??to??be??updated."
???????? Else
???????????? errorMessage??=??"MediaFailed:??"??&??_
???????????????????????? +??e.ErrorException.Message??+??"."
???????? End??If
???????? System.Windows.Browser.HtmlPage.Window.Alert(errorMessage)
???? End??Sub

???? '??makes??license??request??explicitly
???? Public??Class??ManualLicenseAcquirer
???????? Inherits??LicenseAcquirer

???????? Private??challengeString??As??String

???????? Private??_mediaElementName??As??String

???????? Public??Sub??New(ByVal??mediaElementName??As??String)
???????????? MyBase.New
???????????? _mediaElementName??=??mediaElementName
???????? End??Sub

???????? '??The??default??implementation??of??OnAcquireLicense??calls??into??the?? MediaElement??to??acquire??a
???????? '??license.??It??is??called??when??the??Media??pipeline??is??building??a?? topology??and??will??be??raiser
???????? '??before??MediaOpened??is??raised.
???????? Protected??Overrides??Sub??OnAcquireLicense(ByVal??licenseChallenge??As?? System.IO.Stream,??ByVal??licenseServerUri??As??Uri)
???????????? Dim??sr??As??StreamReader??=??New??StreamReader(licenseChallenge)
???????????? challengeString??=??sr.ReadToEnr
???????????? '??Need??to??resolve??the??URI??for??the??License??Server??--??make??sure??it ??is??correct
???????????? '??and??store??that??correct??URI??as??resolvedLicenseServerUri.
???????????? Dim??resolvedLicenseServerUri??As??Uri
???????????? If??(LicenseServerUriOverride??Is??Nothing)??Then
???????????????? resolvedLicenseServerUri??=??licenseServerUri
???????????? Else
???????????????? resolvedLicenseServerUri??=??LicenseServerUriOverride
???????????? End??If
???????????? '??Make??a??HttpWebRequest??to??the??License??Server.
???????????? Dim??request??As??HttpWebRequest??=??CType(WebRequest.Create (resolvedLicenseServerUri),HttpWebRequest)
???????????? request.Method??=??"POST"
???????????? '??Set??ContentType??through??property
???????????? request.ContentType??=??"application/xml"
???????????? '??ADD??REQUIRED??HEADERS.
???????????? '??The??headers??below??are??necessary??so??that??error??handling??and?? redirects??are??handler
???????????? '??properly??via??the??Silverlight??client.
???????????? request.Headers("msprdrm_server_redirect_compat")??=??"false"
???????????? request.Headers("msprdrm_server_exception_compat")??=??"false"
???????????? '??Initiate??getting??request??stream
???????????? Dim??asyncResult??As??IAsyncResult??=??request.BeginGetRequestStream(New?? AsyncCallback(RequestStreamCallback),??request)
???????? End??Sub

???????? '??This??method??is??called??when??the??asyncrhonous??operation??completes.
???????? Private??Sub??RequestStreamCallback(ByVal??ar??As??IAsyncResult)
???????????? Dim??request??As??HttpWebRequest??=??CType(ar.AsyncState,HttpWebRequest)
???????????? '??populate??request??stream
???????????? request.ContentType??=??"text/xml"
???????????? Dim??requestStream??As??Stream??=??request.EndGetRequestStream(ar)
???????????? Dim??streamWriter??As??StreamWriter??=??New??StreamWriter(requestStream,?? System.Text.Encoding.UTF8)
???????????? streamWriter.Write(challengeString)
???????????? streamWriter.Close
???????????? '??Make??async??call??for??response
???????????? request.BeginGetResponse(New??AsyncCallback(ResponseCallback),??request)
???????? End??Sub

???????? Private??Sub??ResponseCallback(ByVal??ar??As??IAsyncResult)
???????????? Dim??request??As??HttpWebRequest??=??CType(ar.AsyncState,HttpWebRequest)
???????????? Dim??response??As??WebResponse??=??request.EndGetResponse(ar)
???????????? SetLicenseResponse(response.GetResponseStream)
???????? End??Sub
???? End??Class
End??Class

C#

public partial class Page : UserControl
{
    public Page()
    {
      InitializeComponent();
      this.Loaded += new RoutedEventHandler(Page_Loaded);
    }
    void Page_Loaded(object sender, RoutedEventArgs e)
    {
      // Test a full fledged manual acquirer
      // Set the LicenseAcquirer of the MediaElement to the custom License Aquirer
      // defined in this sample.
      myME.LicenseAcquirer = new ManualLicenseAcquirer(myME.Name);
      // Set the License URI to proper License Server address.
      myME.LicenseAcquirer.LicenseServerUriOverride = new Uri

("http://contoso.com/myLicenseServer.asmx", UriKind.Absolute);
      myME.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>

(myME_MediaFailed);
      // Set the source of the MediaElement to the URL of the media encrypted with WMDRM.
      myME.Source = new Uri(“http://contoso.com/wmdrm_url.wmv”, UriKind.Absolute);
    }
    void myME_MediaFailed(object sender, ExceptionRoutedEventArgs e)
    {
      string errorMessage = "";
      if (e.ErrorException.ToString().Contains(" 6001 "))
      {
          errorMessage = "The individualization component software failed to" +
                         " download to the user’s computer. This error would" +
                         " come up when the MediaElement is in the 

Individualizing" +
                         " MediaElementState. One possible reason for this error 

is" +
                         " that the Silverlight client cannot connect the 

Microsoft" +
                         " Individualization Server.";
      }
      else if (e.ErrorException.ToString().Contains(" 6004 "))
      {
          errorMessage = " The installation of Silverlight on the client is" +
                         " out of date and needs to be updated.";  
      }
      else
      {
          errorMessage = "MediaFailed: " + e.ErrorException.Message + 

".";
      }
      System.Windows.Browser.HtmlPage.Window.Alert(errorMessage);
    }
    // makes license request explicitly
    public class ManualLicenseAcquirer : LicenseAcquirer
    {
      private string challengeString;
      string _mediaElementName;
    public ManualLicenseAcquirer(string mediaElementName)
    {
      _mediaElementName = mediaElementName;
    }
    // The default implementation of OnAcquireLicense calls into the MediaElement to acquire 

a
    //  license. It is called when the Media pipeline is building a topology and will be 

raised
    // before MediaOpened is raised.
    protected override void OnAcquireLicense(System.IO.Stream licenseChallenge, Uri 

licenseServerUri)
    {
      StreamReader sr = new StreamReader(licenseChallenge);
      challengeString = sr.ReadToEnd();
      // Need to resolve the URI for the License Server -- make sure it is correct
      // and store that correct URI as resolvedLicenseServerUri.
      Uri resolvedLicenseServerUri;
      if (LicenseServerUriOverride == null)
        resolvedLicenseServerUri = licenseServerUri;
      else
      resolvedLicenseServerUri = LicenseServerUriOverride;
      // Make a HttpWebRequest to the License Server.
      HttpWebRequest request = WebRequest.Create(resolvedLicenseServerUri) as 

HttpWebRequest;
      request.Method = "POST";
      // Set ContentType through property    
      request.ContentType = "application/xml";
      //  ADD REQUIRED HEADERS.
      // The headers below are necessary so that error handling and redirects are handled 
      // properly via the Silverlight client.
      request.Headers["msprdrm_server_redirect_compat"] = "false";
      request.Headers["msprdrm_server_exception_compat"] = "false";
      //  Initiate getting request stream  
      IAsyncResult asyncResult = request.BeginGetRequestStream(new AsyncCallback

(RequestStreamCallback), request);
    }
    // This method is called when the asynchronous operation completes.
    void RequestStreamCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;
      // populate request stream  
      request.ContentType = "text/xml";
      Stream requestStream = request.EndGetRequestStream(ar);
      StreamWriter streamWriter = new StreamWriter(requestStream, 

System.Text.Encoding.UTF8);
      streamWriter.Write(challengeString);
      streamWriter.Close();
      // Make async call for response  
      request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
    }
    private void ResponseCallback(IAsyncResult ar)
    {
      HttpWebRequest request = ar.AsyncState as HttpWebRequest;
      WebResponse response = request.EndGetResponse(ar);
      SetLicenseResponse(response.GetResponseStream());
    }
  }
}

Silverlight DRM 脱机方案

某些用户目前没有可用的带宽来通过 Internet 观看高质量视频。他们确实具有高速连接,可用于下 载内容供以后观看。其他用户可能希望先下载电影,供以后在网络不可用时观看,例如,在飞机上或在朋 友的家里(没有 Internet 连接)。能够向脱机内容提供数字版权管理 (DRM),但仍然具有增强的保护功 能,这对于启用各种内容发布业务方案(如媒体采购、订阅和租赁等)都是关键所在。

基本脱机 DRM(一次性购买)

或许最简单的脱机方案是用户购买一段内容,然后将其下载到计算机上,需要时进行播放。

因为用户正在试图脱机播放受保护的内容,所以,许可证验证也需要脱机发生。为此,已下载内容需 要的许可证存储在称为持久性许可证存储区的位置,此存储区是在初始化期间在用户的计算机上创建的( 请参阅本文前面的 Silverlight DRM 联机概略性概述)。当用户试图播放脱机内容时,内容将通过在持 久性许可证存储区中查找其对应的许可证尝试验证播放。您可以在枚举许可证一节中了解有关枚举这些许 可证的更多信息。

在下载之前验证许可证

在脱机方案中,用户下载内容文件,然后播放它。由于下载媒体文件可能要花时间和带宽,因此,请 考虑在允许下载之前验证用户的许可证,而不是在用户尝试播放时进行验证。下面的示例演示如何执行此 操作。

下面的应用程序使用一个密钥标识符和一个身份验证标记将许可证获取请求发送到许可证服务器。许 可证服务器将响应一个许可证以及从中下载内容的 URL。

C#

// Called when the user is online and wants to download some protected 

content.
public void GetLicensePreDelivery(string customData,
                                     Guid keyId)
{
    Uri licenseServerUrl = new Uri("http://contoso.com/myLicenseServer.asmx");
    LicenseAcquirer acquirer = new LicenseAcquirer();
    acquirer.ChallengeCustomData = customData;
    // Set the License URI to proper License Server address.
    acquirer.LicenseServerUriOverride = licenseServerUrl;
    acquirer.AcquireLicenseCompleted += new 

EventHandler<AcquireLicenseCompletedEventArgs>(acquirer_Completed);
    acquirer.AcquireLicenseAsync(keyId, ContentKeyType.Aes128Bit, Guid.Empty);
}

AcquireLicenseAsync 调用在启动许可证获取之后完成,而无需等待长时间的内容下载操作完成。当 许可证获取确实完成后,将调用在 AcquireLicenseCompleted 事件上配置的委托。在此示例中,这是 acquirer_Completed 方法,它可能类似下面示例中的内容。

C#

public void acquirer_Completed(object sender, AcquireLicenseCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // take appropriate action.  Might be retrying for instance.
    }
    else if (e.Cancelled)
    {
        // take appropriate action.  Might be nothing.
    }
    else
    {
        //
        //  We acquired the license successfully, go ahead and download
        //  the content.  Note the service decided to stash the content 
        //  url in the LicenseAcquirer response custom data.
        //
        string contentAcquisitionUrl = e.ResponseCustomData;
        DownloadContent(contentAcquisitionUrl);
    }
}

管理哪些计算机可以播放内容(域)

Microsoft PlayReady 域特性提供的这一功能对于最终用户体验而言很直观:服务提供商允许用户将 一组计算机指定为一个域。如果域中的任何计算机对于内容具有域绑定的许可证,则其中的任何计算机都 可以使用域中任何其他计算机获取的、受 Microsoft PlayReady 保护的内容。用户可以轻松地在域中添 加或删除计算机,只要域中的计算机总数不超过此服务定义的限制即可。

下图显示了域管理在概念上如何适合总体 DRM 过程:

PlayReady 域服务器(域控制器)是用于确定域所表示的内容(例如,用户、家庭或一组用户)且具 有与该域关联的实体列表的服务器。域服务器还实行用于定义域中可以容纳多少台计算机的策略。自始至 终,域控制、分发和授予许可等都可以在单独的服务器上或同一台服务器上完成,具体取决于性能需要。 为了清楚起见,上图将它们显示为单独的服务器。

使用域绑定许可证的许多媒体应用程序希望在第一次运行应用程序时将客户端加入用户的域。这使得 服务可以控制每个用户有权访问媒体内容的客户端数目。您不能使用 Silverlight API 枚举这些域。因 此,您将希望让应用程序自行保留状态数据,以了解客户端是否已加入到域。

下面的简单示例演示如何使用 DomainAcquirer 类在第一次启动应用程序时实现加入域的请求。

C#

Guid c_ServiceId = new Guid("{deb47f00-8a3b-416d-9b1e-5d55fd023044}");
Uri c_DomainServerUrl = new Uri

("http://domainserver.contoso.com/rmsdk/rightsmanager.asmx");
Uri c_LicenseServerUrl = new Uri

("http://licenseserver.contaso.com/rmsdk/rightsmanager.asmx");
public void acquirer_JoinDomainCompleted(object sender, DomainOperationCompletedEventArgs e)
{
    if (e.Error != null)
    {
        // Standard error handling may include logging the error, 
        // retrying, or reporting failure to the user
        // e.CustomData may have additional information depending on 
        // the type of error is reported in e.Message    
    }
    else if (e.Cancelled)
    {
        // Standard cancellation handling
    }
    else
    {
        // Update the ISO store that we are joined to the domain
        // The application may want to store e.AccountId
    }
}
public void JoinDomainOnFirstUse()
{
    if (false == IsJoinedToDomain())
    {
        string friendlyName = PromptUserForClientFriendlyName();
        DomainAcquirer acquirer = new DomainAcquirer();
        acquirer.JoinDomainCompleted +=new 
            EventHandler<JoinDomainCompletedEventArgs>(
            acquirer_JoinDomainCompleted);
        acquirer.JoinDomainAsync(c_ServiceId, 
                                 Guid.Empty, 
                                 c_DomainServerUrl,
                                 friendlyName);
    }
}

您可能希望通过允许用户转到帐户的属性页来提供注销客户端的功能。例如,您可以为当前在域中的 每台设备提供一个“注销此客户端”按钮,并提供一个“添加新客户端”按钮以将其他设备加到域中。如 果用户注销当前客户端,则执行“保留域”操作以便从客户端的持久性许可证存储区中删除域键。通过这 种方式,您可以控制可以播放受控制内容的客户端数,并且用户可以控制它们是哪些客户端。

但是,如果当用户从某个客户端(客户端 y)访问在线帐户属性页时,从域中删除了另一个客户端( 客户端 x),将发生什么呢?由于从域中删除客户端 x 时该客户端从 Internet 断开连接,但客户端 x 的永久性许可证存储区中的域许可证并没有获得删除通知,因此,仍然可以在客户端 x 上播放内容。

许多服务具有严格的业务规则来控制此类注销操作。例如,它们可能限制可通过这种方式注销的设备 数,要求调用客户服务来执行注销,或应用欺诈性检测逻辑。因此,执行“保留域”操作是从域中删除客 户端的首选方式。下面示例中的逻辑说明可能实现“注销此客户端”按钮的方式。

C#

public void RemoveClientFromAccountButton_OnClick(object sender,
                                                  RoutedEventArgs e)
{
    //
    // The service may want to prompt the user with a "Are you sure?"
    // prompt before removing the client as it will disable media
    // playback of any domain bound content.
    //
    // The service will want to look up the currently logged in user’s
    // account identifier from the ISO store.  The accountId parameter
    // is strictly required, and it is the responsibility of the
    // service to ensure that is is available at this point.
    //
    Guid m_AccountId = accountId;
    DomainAcquirer acquirer = new myDomainAcquirer();
    acquirer.LeaveDomainCompleted += new
        EventHandler<LeaveDomainCompletedEventArgs>(
        acquirer_LeaveDomainCompleted);
    acquirer.LeaveDomainAsync(c_ServiceId,
                              m_AccountId,
                              c_DomainServerUrl);
}
public void acquirer_LeaveDomainCompleted(object sender, DomainOperationCompletedEventArgs 

e)
{
    if (e.Error != null)
    {
        // Error handling may include logging the error, retrying, or
        // reporting failure to the user e.CustomData may have
        // additional information depending on the type of error is
        // reported in e.Message
    }
    else if (e.Cancelled)
    {
        // Handle cancel
    }
    else
    {
        // Update the ISO store that we left the domain.  Likely means
        // cleaning up the domain object for the given AccountId.
    }
}

注意:LeaveDomainAsync 可能会失败(可能是客户端未连接到 Internet),但仍将从域中删除客户 端。在这种情况下,客户端认为它们不是域的一部分,但服务仍可能会认为客户端是域的一部分。该服务 必须提供一种方法来协调这种不匹配。

许可证获取代码(无论是通过 MediaElement 获取,还是使用 LicenseAcquirer 直接获取)理解从许 可证服务器发送回的 RenewDomainException 和 DomainRequiredException 错误(请参见本文前面的错 误处理)。如果客户端收到以下错误之一,它将尝试使用 DomainAcquirer(无论是默认实例还是用户配 置的实例),以使用在域错误消息中提供的参数来执行“加入域”操作。下面示例中的逻辑说明要利用此 功能几乎不需要在 API 级别执行操作:

C#

public void RenewDomain()
{
    LicenseAcquirer myLicenseAcquirer = new LicenseAcquirer();
    myLicenseAcquirer.DomainAcquirer = new myDomainAcquirer();
    mediaElement.LicenseAcquirer = myLicenseAcquirer;
    mediaElement.LicenseAcquirer.LicenseServerUriOverride =
        c_LicenseServerUrl;
    mediaElement.Source = new
        Uri("http://contoso.com/content.wmv");
    //
    //  If the license server decides that the client does not have a
    //  domain membership, the domain membership is out of date,
    //  then a DomainRequiredException or RenewDomainException respectively
    //  will be thrown and the client will send back a response containing
    //  the necessary information (url, serviceid, accountid, etc) to
    //  send to the domain server.  The license acquisition pipeline
    //  would treat this somewhat like an Indiv message in that
    //  it would do the join domain and then restart the license
    //  acquisition.
    //
    //  Note that a customized DomainAcquirer was provided so the
    //  OnJoinDomain method will be called to allow
    //  authentication information to be provided with the Join Domain
    //  request.
    //
    mediaElement.Play();
}

租赁和订阅

启用租赁、订阅或同时启用两者比只是购买内容要更为复杂,因为您需要构建更复杂的 LicenseServer 逻辑来进行许可证管理。例如,如果用户下载他们所租赁的内容,则您需要在许可证中指 定许可证何时以及在什么情况下过期。许可证可能在最初播放的 24 小时之后或下载的 30 天之后过期( 以先到者为准)。

租赁和订阅协议存储在用户的持久性许可证存储区上的许可证中。在播放内容之前,需要找到和验证 位于持久性许可证存储区上的正确许可证。在讨论如何遍历许可证之前,先了解许可证的不同类型以及如 何将它们链接起来以启用特定方案。

根许可证、叶许可证和许可证链

许可证是保留资产(另一个许可证或一段内容)的解密密钥的数据文件。它还包含 DRM 权限和限制, 这些内容定义如何可以使用它赋予访问权限的资产。许可证有三种不同类型:

简单许可证:从通过使用 PlayReady Server SDK 构建的应用程序中提供的 PlayReady 许可证,其中 包含权限和限制以及用于关联内容段的密钥。

根许可证:控制一个或更多叶许可证的许可证。叶许可证控制着特定内容段的播放,而根许可证控制 所有内容段的播放。例如,在订阅模型中,根许可证可能具有到期日期,而叶许可证则没有。当根许可证 到期时,叶许可证将不可用,直至获得新的根许可证。

叶许可证:依赖于根许可证的简单许可证。

当您具有受单一根许可证控制的叶许可证时,就认为这些许可证构成了许可证“链”。下图说明这一 概念:

现在讨论用户具有订阅并下载了若干视频供以后脱机播放的情况。对于每个视频,都有一个叶许可证 指定允许使用该视频。在此情况下,我们假设叶节点规定用户可以随时播放此视频。但是,PlayReady 确 保在允许播放之前具有有效的根许可证。如果根许可证过期(或许因为用户允许其订阅过期),则叶许可 证不允许播放。这样,就可以使用根许可证来控制整个订阅(用户设备上的所有叶许可证)。

说明:

叶许可证可以具有多个根许可证。在这种情况下,至少有一个根许可证有效,才能进行播放。此外, 叶许可证可以脱离根许可证而存在。

枚举许可证

您可以通过迭代永久性许可证存储区中的所有许可证(MediaLicense 对象)来检查许可证或许可证链 是否过期。如果任何许可证需要更新,您可以添加逻辑以试图连接到授权服务器,进行必要的更新,并提 示用户付款等等。

下面的示例演示如何检查是否需要续订订阅许可证。请注意,用户需要在浏览器之外运行 Silverlight,许可证枚举的提升的信任才有可能。

C#

private void CheckSubscriptionRootForRenewal(Guid parentKeyId,
                                             Uri licenseServerUrl)
{
    DateTimeOffset renewalDate = DateTimeOffset.Now.AddDays(5);
    // Query the licensemanager to see if we have a usable root license
    IEnumerable<MediaLicense> myLicenses = LicenseManagement.SelectLicenses

(parentKeyId);
    bool renewRoot = true;
    foreach (MediaLicense ML in myLicenses)
    {
        // If the license expires within the next 5 days,
        // renew the subscribtion by requesting a new root license.
        if ((ML.Usable) &&
            (ML.ExpirationDate > renewalDate))
        {
            renewRoot = false;
            break;
        }
    }
    if (renewRoot)
    {
        LicenseAcquirer acquirer = new LicenseAcquirer();
        acquirer.LicenseServerUriOverride = licenseServerUrl;
        acquirer.AcquireLicenseCompleted += new 

EventHandler<AcquireLicenseCompletedEventArgs>(acquirer_Completed);
        acquirer.AcquireLicenseAsync(parentKeyId, ContentKeyType.Aes128Bit, Guid.Empty);
    }

在此示例中,您将迭代永久性许可证存储区中的所有 MediaLicense 实例。MediaLicense 实例可以是 以下任意一项:

许可证链(叶加根)

一个简单许可证

单个叶许可证(根许可证不存在)

单个根许可证(直接查询根)

下面的函数可用于筛选可能播放选项列表中向用户显示的内容列表,尤其是当用户处于脱机状态而无 法获取新许可证时。它还可用于决定是否在进入脱机状态之前获得许可证。对于订阅客户,如果用户处于 联机状态,则应首先调用 CheckSubscriptionRootForRenewal 函数(在前面的示例中)。

C#

public bool IsUsableLicenseAvailableForContent(System.IO.Stream contentFile)
{
    bool returnValue = false;
    // SelectLicenses works only if the user is running the Silverlight application offline
    // *and* elevated trust.
    IEnumerable<MediaLicense> myLicenses = LicenseManagement.SelectLicenses

(contentFile);
    foreach (MediaLicense ML in myLicenses)
    {
        if (ML.Usable)
        {
            returnValue = true;
            break;
        }
    }
    return returnValue;
}

在传输期间增强内容包括(输出保护)

输出保护的目的是在计算机的视频或音频输出端口与设备显示器或扬声器的输入端口(输出)之间进 行传输期间增强对于内容的保护。输出保护在许可证中指定,因此,许可证服务器控制着使用输出保护的 内容。有关更多信息,请参见输出保护:

http://blogs.msdn.com/b/silverlight_sdk/archive/2010/07/09/silverlight-output- protection.aspx

转载注明地址:http://www.chengxuyuans.com/slverlight/28289.html