【问题标题】:Silverlight RIA Services - How To Best Handle Client Auth Session Timeout?Silverlight RIA 服务 - 如何最好地处理客户端身份验证会话超时?
【发布时间】:2011-10-30 23:33:15
【问题描述】:

我使用 Silverlight4、RIA 服务构建了一个应用程序,并且我正在使用 ASP.NET Membership 进行身份验证/授权。

我的 web.config 有这个:

<system.web>
 <sessionState timeout="20"/>
 <authentication mode="Forms">
  <forms name="_ASPXAUTH" timeout="20"/>
 </authentication>

我已经阅读了许多关于如何在客户端处理身份验证/会话超时的不同策略。也就是说:如果客户端空闲了 x 分钟(此处为 20 分钟),然后他们对触发 RIA/WCF 调用的 UI 执行了某些操作,我想捕获该事件并进行适当处理(例如,将它们带回登录屏幕)——简而言之:我需要一种方法来区分真正的服务器端 DomainException 和身份验证失败,因为会话超时。

AFAIK:没有类型的异常或属性可以确定这一点。我能够确定这一点的唯一方法 - 这似乎是一个黑客:检查错误的消息字符串并寻找类似“拒绝访问”或“拒绝”的内容。例如:像这样:

if (ex.Message.Contains("denied"))
  // this is probably an auth failure b/c of a session timeout

所以,这就是我目前正在做的事情,如果我使用 VS2010 的内置服务器运行和调试,或者我在 localhost IIS 中运行,它就可以工作。如果我将超时设置为 1 分钟,登录,等待超过一分钟并触发另一个调用,我在异常上断点并输入上面的 if 代码块,一切都很好。

然后我将应用程序部署到远程 IIS7 服务器并尝试相同的测试,但它不起作用。所以,我添加了日志跟踪,这是发生异常的事件:

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
 <System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
  <EventID>131076</EventID>
  <Type>3</Type>
  <SubType Name="Error">0</SubType>
  <Level>2</Level>
  <TimeCreated SystemTime="2011-10-30T22:13:54.6425781Z" />
  <Source Name="System.ServiceModel" />
  <Correlation ActivityID="{20c26991-372f-430f-913b-1b72a261863d}" />
  <Execution ProcessName="w3wp" ProcessID="4316" ThreadID="24" />
  <Channel />
  <Computer>TESTPROD-HOST</Computer>
 </System>
 <ApplicationData>
  <TraceData>
   <DataItem>
    <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error">
     <TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.Diagnostics.TraceHandledException.aspx</TraceIdentifier>
     <Description>Handling an exception.</Description>
     <AppDomain>/LM/W3SVC/1/ROOT/sla-2-129644844652558594</AppDomain>
     <Exception>
      <ExceptionType>System.ServiceModel.FaultException`1[[System.ServiceModel.DomainServices.Hosting.DomainServiceFault, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
      <Message></Message>
       <StackTrace>
        at System.ServiceModel.DomainServices.Hosting.QueryOperationBehavior`1.QueryOperationInvoker.InvokeCore(Object instance, Object[] inputs, Object[]&amp; outputs)
        at System.ServiceModel.DomainServices.Hosting.DomainOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs)
        at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
        at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
        at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)
        at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
     </StackTrace>
     <ExceptionString>System.ServiceModel.FaultException`1[System.ServiceModel.DomainServices.Hosting.DomainServiceFault]:  (Fault Detail is equal to System.ServiceModel.DomainServices.Hosting.DomainServiceFault).</ExceptionString>
  </Exception>
 </TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>

问题是我在错误消息中没有指示“拒绝”或“访问被拒绝”的字符串 - 我不确定为什么此解决方案适用于 localhost IIS 或 VS2010 主机,但不适用于远程IIS7 服务器。我在这里缺少一些晦涩的配置设置吗?一般来说,有没有更好的方法来做到这一点?

【问题讨论】:

    标签: silverlight silverlight-4.0 asp.net-membership wcf-ria-services


    【解决方案1】:

    你现在可能已经明白了,但是this article 描述了使用 DomainOperationException 并检查错误代码。

    dex.ErrorCode == ErrorCodes.NotAuthenticated || dex.ErrorCode == ErrorCodes.Unauthorized
    

    为了方便访问(如果我们无法访问博客)这里是 Josh Eastburn 的博客文章:

    使用 Silverlight 和 WCF RIA 服务的开发人员经常会提出一个问题:为什么我的 Silverlight 应用程序在空闲一段时间后会抛出异常?如您所料,这是由于经过身份验证的会话超时。但这并不是那么简单。由于 Silverlight 使用客户端/服务器体系结构,客户端可以在无限期独立于服务器运行。只有当 Silverlight 客户端调用服务器时,才会实现服务器端超时。有几个选项可以处理客户端-服务器超时问题(您可能会想出更多):如果您不关心删除会话超时的安全隐患,您可以增加超时在 web.config 中设置,或者在 Silverlight 客户端中创建一个 DispatcherTimer,它调用服务器上的一个简单方法来充当“保持活动状态”。将 DispatcherTimer 添加到与服务器端超时保持同步的 Silverlight 客户端,并警告/提示用户在时间到期之前保持会话处于活动状态,或者让他们在会话已到期时重新进行身份验证。但是,这需要额外的努力以在发出新的服务器请求时使计时器保持同步。允许服务器像往常一样处理超时,并在 Silverlight 客户端上优雅地处理超时。这意味着超时由服务器调用活动确定,而不是限制 Silverlight 客户端的活动(即在上下文中访问客户端数据)。在这三个选项中,我发现第三个是安全性和可用性的最佳平衡,同时又不会给应用程序增加不必要的复杂性。为了全局处理这些服务器端超时,您可以在 App.xaml.cs 中的 Application_UnhandledException 方法或全局 ViewModel 加载构造(如果有)中添加以下逻辑:

     // Check for Server-Side Session Timeout Exception
     var dex = e.ExceptionObject as DomainOperationException; 
     if ((dex != null) && (dex.ErrorCode == ErrorCodes.NotAuthenticated || dex.ErrorCode == ErrorCodes.Unauthorized) && WebContext.Current.User.IsAuthenticated) 
     {
        // A server-side timeout has occurred.  Call LoadUser which will automatically
        //   authenticate if "Remember Me" was checked, or prompt for the user to log on again
        WebContext.Current.Authentication.LoadUser(Application_UserLoaded, null);
        e.Handled = true; 
     }
    

    ErrorCodes 类中定义了以下常量:

    public static class ErrorCodes 
    {
         public const int NotAuthenticated = 0xA01;
         public const int Unauthorized = 401; 
    }  
    

    当服务器端会话超时时,任何后续调用都将返回 DomainOperationException。通过检查返回的 ErrorCode,您可以确定它是否是身份验证错误并进行相应处理。在我的示例中,我正在调用 WebContext.Current.Authentication.LoadUser() ,如果可能,它将尝试重新验证用户。即使用户无法自动重新认证,它也会回调我的 Application_UserLoaded 方法。在那里我可以检查 WebContext.Current.User.IsAuthenticated 以确定是否继续之前的操作,或者我是否需要重定向回主页并重新提示登录。以下是 Appliation_UserLoaded 回调中的一些代码示例,如果用户未通过身份验证,则会显示登录对话框:

    // Determine if the user is authenticated
    if (!WebContext.Current.User.IsAuthenticated) 
    {
        // Show login dialog automatically
        LoginRegistrationWindow loginWindow = new LoginRegistrationWindow();
        loginWindow.Show(); 
    }   
    

    要测试您的代码,您可以将 web.config 中的超时值设置为 值小,所以超时很快发生:

    <authentication mode="Forms">   
         <forms name=".Falafel_ASPXAUTH" timeout="1" /> 
    </authentication>   
    

    如果您想在有效的解决方案中查看所有这些代码,请查看我们的Silverlight RIA Template on CodePlex

    【讨论】:

    • 谢谢——这正是我想要的。我在那个博客上列出了选项 3,但还没有时间把它做好。这应该对我有用。
    猜你喜欢
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多