我的web.config有这个:
<system.web> <sessionState timeout="20"/> <authentication mode="Forms"> <forms name="_ASPXAUTH" timeout="20"/> </authentication>
关于如何在客户端处理auth / session timeout,我已经阅读了很多不同的策略.也就是说:如果客户端空闲x分钟(这里是20),然后他们用触发RIA / WCF调用的UI做一些事情,我想要捕获该事件并适当处理(例如将它们带回到登录屏幕) – 简而言之:我需要一种方法来区分真正的服务器端DomainException与auth失败,因为会话超时.
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,PublicKeyToken=b77a5c561934e089</ExceptionType> <Message></Message> <StackTrace> at System.ServiceModel.domainservices.Hosting.QueryOperationBehavior`1.QueryOperationInvoker.InvokeCore(Object instance,Object[] inputs,Object[]& outputs) at System.ServiceModel.domainservices.Hosting.DomainoperationInvoker.Invoke(Object instance,Object[]& outputs) at System.ServiceModel.dispatcher.dispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.dispatcher.ImmutabledispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.dispatcher.ImmutabledispatchRuntime.ProcessMessage31(MessageRpc& 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服务器中无效.我在这里缺少一些不起眼的配置设置吗?有没有更好的方法来做到这一点?
解决方法
dex.ErrorCode == ErrorCodes.NotAuthenticated || dex.ErrorCode == ErrorCodes.Unauthorized
为方便访问(如果我们无法访问博客),这里是Josh Eastburn撰写的博客文章:
A question that comes up often from developers who are working with Silverlight and WCF RIA Services: why does my Silverlight application throw an exception when it has been idle for a period of time? As you might expect,it is due to the authenticated session timing out. But it isn’t quite that straightforward. Because Silverlight uses a client/server architecture,the client can operate independent of the server for an indefinite period of time. It is only when the Silverlight client makes a call to the server that the server-side timeout is realized. There are a few options to handle the client-server timeout issue (and you may be able to come up with a few more): If you aren’t concerned with the security implications of removing a session timeout,you can either increase the timeout setting in web.config,or create a dispatcherTimer in the Silverlight client that calls a simple method on the server to act as a “Keep Alive.” Add a dispatcherTimer to the Silverlight client that stays in sync with the server-side timeout and warn/prompt the user keep the session active before the time expires or have them re-authenticate if it has already expired. However,this requires extra effort to keep the timers in sync when new server requests are made. Allow the server to handle the timeout as it normally would and handle the timeout gracefully on the Silverlight client. This means that the timeout is determined by server call activity,NOT activity confined the Silverlight client (i.e. accessing client-side data in the context). Of these three options,I find the third to be the best balance of security and usability while at the same time not adding unnecessary complexity to the application. In order to handle these server-side timeouts globally,you can add the following logic in either the Application_UnhandledException method in App.xaml.cs or in your global viewmodel loading construct if you have one:
// 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; }
The following constants are defined within the ErrorCodes class:
public static class ErrorCodes { public const int NotAuthenticated = 0xA01; public const int Unauthorized = 401; }
When the server-side session times out,any subsequent calls will return a DomainoperationException. By inspecting the returned ErrorCode,you can determine if it is an authentication error and handle it accordingly. In my example,I am calling WebContext.Current.Authentication.LoadUser() which will attempt to re-authenticate the user if possible. Even if the user can not be automatically re-authenticated,it will call back to my Application_UserLoaded method. There I can check WebContext.Current.User.IsAuthenticated to determine whether to proceed with the prevIoUs operation or if I need to redirect back to the home page and reprompt for login. Here is an example of some code in the Appliation_UserLoaded callback that shows a login dialog if the user is not authenticated:
// Determine if the user is authenticated if (!WebContext.Current.User.IsAuthenticated) { // Show login dialog automatically LoginRegistrationWindow loginWindow = new LoginRegistrationWindow(); loginWindow.Show(); }
To test your code,you can set your timeout value in web.config to a
small value so timeouts occur quickly:
<authentication mode="Forms"> <forms name=".Falafel_ASPXAUTH" timeout="1" /> </authentication>
If you’d like to see all of this code in a working solution,check out our 07001.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。