8

Tôi đã xây dựng một ứng dụng với Silverlight4, RIA Services và tôi đang sử dụng ASP.NET Membership để xác thực/ủy quyền.Dịch vụ Silverlight RIA - Làm thế nào để xử lý tốt nhất Client Auth Session Timeout?

web.config của tôi có này:

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

Tôi đã đọc một số chiến lược khác nhau về cách đối phó với thời gian chờ auth/phiên trên các mặt hàng. Đó là: nếu máy khách không hoạt động trong x phút (20 ở đây), và sau đó họ làm điều gì đó với giao diện người dùng kích hoạt cuộc gọi RIA/WCF, tôi muốn bẫy vào sự kiện đó và xử lý một cách thích hợp (ví dụ: đưa họ trở lại màn hình đăng nhập) - Tóm lại: Tôi cần một cách để phân biệt với một DomainException phía máy chủ đang tồn tại và một lỗi auth vì phiên đã hết thời gian chờ.

AFAIK: không có ngoại lệ hoặc thuộc tính được nhập có thể xác định điều này. Cách duy nhất tôi đã có thể xác định điều này - mà có vẻ như một hack: là để kiểm tra chuỗi tin nhắn của lỗi và tìm kiếm một cái gì đó như "Truy cập bị từ chối" hoặc "bị từ chối". Ví dụ: một cái gì đó như thế này:

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

Vì vậy, đây là những gì tôi đang làm, và nó hoạt động nếu tôi chạy và gỡ lỗi với built-in máy chủ từ VS2010, hoặc nếu tôi chạy trong localhost IIS . Nếu tôi đặt thời gian chờ là 1 phút, hãy đăng nhập, chờ hơn một phút và kích hoạt một cuộc gọi khác, tôi sẽ phân tích ngoại lệ và nhập khối mã nếu ở trên và tất cả đều tốt.

Sau đó, tôi triển khai ứng dụng đến máy chủ IIS7 từ xa và tôi thử cùng một thử nghiệm và nó không hoạt động. Vì vậy, tôi đã thêm log truy tìm, và đây là sự kiện mà các ngoại lệ đã xảy ra:

<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> 

Vấn đề là tôi không có chuỗi trong thông báo lỗi cho biết "bị từ chối" hoặc "Truy cập bị từ chối" - và Tôi không chắc chắn là tại sao giải pháp này hoạt động trong localhost IIS hoặc VS2010 lưu trữ nhưng không phải trong một máy chủ IIS7 từ xa. Có một số thiết lập cấu hình tối nghĩa mà tôi đang thiếu ở đây không? Có cách nào tốt hơn để làm điều này nói chung?

Trả lời

10

Bạn có thể đã nhận được điều này ngay bây giờ, nhưng this article mô tả bằng cách sử dụng DomainOperationException và kiểm tra các mã lỗi.

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

Để truy cập thuận tiện (và trong trường hợp chúng ta truy cập lỏng vào blog) đây là bài viết blog của Josh Eastburn:

Một câu hỏi mà đi lên thường từ nhà phát triển đang làm việc với Silverlight và WCF RIA Services: tại sao ứng dụng Silverlight của tôi lại ném một ngoại lệ khi nó không hoạt động trong một khoảng thời gian? Như bạn có thể mong đợi, đó là do thời gian phiên được xác thực. Nhưng nó không phải là khá đơn giản. Vì Silverlight sử dụng kiến ​​trúc máy khách/máy chủ, máy khách có thể hoạt động độc lập với máy chủ trong một khoảng thời gian không xác định. Chỉ khi máy khách Silverlight thực hiện cuộc gọi đến máy chủ mà thời gian chờ phía máy chủ được thực hiện. Có một vài tùy chọn để xử lý vấn đề thời gian chờ của máy khách (và bạn có thể có thêm một vài vấn đề nữa): Nếu bạn không quan tâm đến các tác động bảo mật của việc xóa thời gian chờ của phiên, bạn có thể tăng thời gian chờ thiết lập trong web.config hoặc tạo DispatcherTimer trong ứng dụng Silverlight gọi một phương thức đơn giản trên máy chủ để hoạt động như một "Keep Alive". Thêm DispatcherTimer vào ứng dụng khách Silverlight vẫn đồng bộ với thời gian chờ phía máy chủ và cảnh báo/nhắc người dùng giữ phiên hoạt động trước khi hết hạn hoặc yêu cầu họ xác thực lại nếu đã hết hạn. Tuy nhiên, điều này đòi hỏi thêm nỗ lực để giữ cho bộ đếm thời gian đồng bộ khi yêu cầu máy chủ mới được thực hiện.Cho phép máy chủ xử lý thời gian chờ như bình thường và xử lý hết thời gian chờ trên máy khách Silverlight. Điều này có nghĩa là thời gian chờ được xác định bởi hoạt động cuộc gọi của máy chủ, KHÔNG hoạt động giới hạn ứng dụng khách Silverlight (tức là truy cập dữ liệu phía máy khách trong ngữ cảnh). Trong ba tùy chọn này, tôi thấy thứ ba là sự cân bằng tốt nhất về bảo mật và khả năng sử dụng trong khi đồng thời không thêm sự phức tạp không cần thiết cho ứng dụng. Để xử lý những timeouts server-side trên toàn cầu, bạn có thể thêm logic sau đây trong cả hai phương pháp Application_UnhandledException trong App.xaml.cs hoặc tải ViewModel toàn cầu của bạn xây dựng nếu bạn có một:

// 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; 
} 

các hằng số sau đây được định nghĩa trong lớp ErrorCodes:

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

Khi lần phiên phía máy chủ ra, bất kỳ subsequ các cuộc gọi ent sẽ trả về một DomainOperationException. Bằng cách kiểm tra ErrorCode trả về, bạn có thể xác định nếu đó là lỗi xác thực và xử lý nó theo đó. Trong ví dụ của tôi, tôi đang gọi WebContext.Current.Authentication.LoadUser() sẽ cố gắng xác thực lại người dùng nếu có thể. Ngay cả khi người dùng không thể tự động được xác thực lại, nó sẽ gọi lại phương thức Application_UserLoaded của tôi. Ở đó tôi có thể kiểm tra WebContext.Current.User.IsAuthenticated để xác định xem có nên tiếp tục với thao tác trước đó hoặc nếu tôi cần chuyển hướng trở lại trang chủ và reprompt để đăng nhập. Đây là một ví dụ về một số mã trong callback Appliation_UserLoaded cho thấy một hộp thoại đăng nhập nếu người dùng không được chứng thực:

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

Để kiểm tra mã của bạn, bạn có thể đặt giá trị thời gian chờ của bạn trong web.config đến một giá trị nhỏ nên timeout xảy ra một cách nhanh chóng:

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

Nếu bạn muốn xem tất cả các mã này trong một giải pháp làm việc, ch eck ra số Silverlight RIA Template on CodePlex của chúng tôi.

+0

Cảm ơn - đây chính xác là những gì tôi đang tìm kiếm. Tôi đã đi xuống tùy chọn 3 được liệt kê trên blog đó, nhưng vẫn chưa có thời gian để làm cho nó đúng. Điều này sẽ làm việc cho tôi. – zenocon