2008-09-11 42 views
13

Tôi đã viết một ứng dụng Silverlight 2 giao tiếp với dịch vụ WCF (BasicHttpBinding). Trang web lưu trữ nội dung Silverlight được bảo vệ bằng cách sử dụng Nhà cung cấp thành viên ASP.NET. Tôi có thể truy cập người dùng hiện tại bằng cách sử dụng HttpContext.Current.User.Identity.Name từ dịch vụ WCF của tôi, và tôi đã bật AspNetCompatibilityRequirementsMode.WCF, Nhà cung cấp dịch vụ thành viên ASP.NET và dịch vụ xác thực

Bây giờ tôi muốn viết một ứng dụng Windows bằng cách sử dụng cùng một dịch vụ web chính xác. Để xử lý xác thực tôi đã kích hoạt Authentication service và có thể gọi là "đăng nhập" để xác thực người dùng của tôi ... Okey, tất cả đều tốt ... Nhưng làm cách nào tôi có được cookie xác thực được đặt trên ứng dụng dịch vụ khác của mình ?!

Cả hai dịch vụ được lưu trữ trên cùng một tên miền

  • MyDataService.svc < - một trong những đối phó với dữ liệu của tôi
  • AuthenticationService.svc < - một trong những ứng dụng cửa sổ có gọi để xác thực.

Tôi không muốn tạo ra một dịch vụ mới cho các cửa sổ khách hàng, hoặc sử dụng một ràng buộc ...

Các dịch vụ ứng dụng Client là một thay thế, nhưng tất cả các ví dụ được giới hạn hiển thị như thế nào để có được người dùng, vai trò và hồ sơ của mình ... Nhưng một khi chúng tôi đã được xác thực bằng cách sử dụng Dịch vụ ứng dụng khách nên có cách để lấy cookie xác thực đó gắn với máy khách dịch vụ của tôi khi gọi lại cho cùng một máy chủ.

Theo thông tin từ các đồng nghiệp là giải pháp bổ sung một wsHttpBinding điểm kết thúc, nhưng tôi hy vọng tôi có thể khắc phục điều đó ...

Trả lời

5

Cuối cùng tôi đã tìm được cách để thực hiện công việc này. Để xác thực, tôi đang sử dụng "WCF Authentication Service". Khi xác thực dịch vụ sẽ cố gắng đặt cookie xác thực. Tôi cần lấy cookie này ra khỏi phản hồi và thêm nó vào bất kỳ yêu cầu nào khác được thực hiện cho các dịch vụ web khác trên cùng một máy. Mã để thực hiện như sau:

var authService = new AuthService.AuthenticationServiceClient(); 
var diveService = new DiveLogService.DiveLogServiceClient(); 

string cookieHeader = ""; 
using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel)) 
{ 
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty(); 
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty; 
    bool isGood = authService.Login("jonas", "jonas", string.Empty, true); 
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties; 
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name]; 
    cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];     
} 

using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel)) 
{ 
    HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty(); 
    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest); 
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader); 
    var res = diveService.GetDives(); 
}  

Như bạn có thể thấy tôi có hai dịch vụ khách hàng, một dịch vụ xác thực và một cho dịch vụ tôi thực sự sẽ sử dụng. Khối đầu tiên sẽ gọi phương thức Đăng nhập và lấy cookie xác thực ra khỏi phản hồi. Khối thứ hai sẽ thêm tiêu đề vào yêu cầu trước khi gọi phương thức dịch vụ "GetDives".

Tôi hoàn toàn không hài lòng với mã này và tôi nghĩ một giải pháp thay thế tốt hơn có thể là sử dụng "Tham chiếu web" thay cho "Tham chiếu dịch vụ" và sử dụng ngăn xếp .NET 2.0.

2

dịch vụ Web, chẳng hạn như những người tạo ra bởi WCF, thường được sử dụng tốt nhất theo cách "không quốc tịch", do đó, mỗi cuộc gọi đến một dịch vụ Web bắt đầu lại. Điều này đơn giản hóa mã máy chủ, vì không cần phải có một "phiên" để nhớ lại trạng thái của máy khách. Nó cũng đơn giản hóa mã máy khách vì không cần phải giữ vé, cookie hoặc các geegaws khác giả định một cái gì đó về trạng thái của máy chủ.

Tạo hai dịch vụ theo cách được mô tả giới thiệu tính trạng thái. Khách hàng được "xác thực" hoặc "không được xác thực" và MyDataService.svc phải tìm ra cái nào.

Khi điều đó xảy ra, tôi đã tìm WCF hoạt động tốt khi nhà cung cấp thành viên được sử dụng để xác thực mỗi cuộc gọi vào một dịch vụ. Vì vậy, trong ví dụ được đưa ra, bạn muốn thêm gubbins xác thực nhà cung cấp thành viên vào cấu hình dịch vụ cho MyDataService và hoàn toàn không có dịch vụ xác thực riêng biệt.

Để biết chi tiết, hãy xem bài viết MSDN here.

[Điều gì rất hấp dẫn về điều này đối với tôi, vì tôi lười biếng, là điều này hoàn toàn mang tính khai báo. Tôi chỉ đơn giản là phân tán các mục cấu hình phù hợp cho MembershipProvider của tôi trong app.config cho ứng dụng và! chơi lô tô! tất cả các cuộc gọi đến mọi hợp đồng trong dịch vụ đều được xác thực.]

Đó là công bằng để lưu ý rằng điều này sẽ không được đặc biệt nhanh chóng. Nếu bạn đang sử dụng SQL Server cho cơ sở dữ liệu xác thực của bạn, bạn sẽ có ít nhất một, có lẽ hai cuộc gọi thủ tục được lưu trữ cho mỗi cuộc gọi dịch vụ. Trong nhiều trường hợp (đặc biệt là đối với các ràng buộc HTTP), chi phí của cuộc gọi dịch vụ sẽ lớn hơn; nếu không, hãy xem xét việc triển khai của riêng bạn về nhà cung cấp thành viên lưu trữ các yêu cầu xác thực.

Một điều mà điều này không cung cấp là khả năng cung cấp khả năng "đăng nhập". Để thực hiện điều đó, bạn có thể cung cấp một hợp đồng dịch vụ (đã được xác thực!) Không thực hiện được gì (ngoài việc tăng lỗi nếu xác thực không thành công), hoặc bạn có thể sử dụng dịch vụ nhà cung cấp thành viên như được mô tả trong bài báo được tham chiếu gốc.

0

Có thể ẩn nhiều mã phụ sau bộ kiểm tra tin nhắn tùy chỉnh & vì vậy bạn không cần phải tự lo việc xử lý bản thân với OperationContextScope.

Tôi sẽ cố gắng thử thứ gì đó sau và gửi cho bạn.

--larsw

+1

Âm thanh tuyệt vời Lars. Hãy cho tôi một ví dụ tốt để chúng tôi có thể "đóng sucker này" xuống;) Chúc mừng, jonas –

0

Bạn nên xem đối tượng CookieContainer trong System.Net. Đối tượng này cho phép một khách hàng không phải trình duyệt để treo vào cookie. Đây là những gì nhóm của tôi đã sử dụng lần cuối cùng chúng tôi gặp phải vấn đề đó.

Here is a brief article cách tiếp tục sử dụng. Có thể có những cái tốt hơn, nhưng điều này sẽ giúp bạn bắt đầu.

Chúng tôi đã đi tuyến đường không quốc tịch cho bộ dịch vụ WCF hiện tại và ứng dụng Silverlight 2 của chúng tôi. Có thể sử dụng Silverlight 2 để làm việc với các dịch vụ liên quan đến bảo mật TransportWithMessageCredential, mặc dù phải mất một số mã bảo mật tùy chỉnh ở phía Silverlight. Kết quả là bất kỳ ứng dụng nào cũng có thể truy cập các dịch vụ đơn giản bằng cách đặt Tên người dùng và Mật khẩu trong tiêu đề thư. Điều này có thể được thực hiện một lần trong một triển khai IRequestChannel tùy chỉnh để các nhà phát triển không bao giờ phải lo lắng về việc tự thiết lập các giá trị. Mặc dù WCF có một cách dễ dàng cho các nhà phát triển để làm điều này mà tôi tin là serviceProxy.Security.Username và serviceProxy.Security.Password hoặc một cái gì đó không kém phần đơn giản.

0

Tôi đã viết thư này trong khi tôi đang sử dụng Dịch vụ ứng dụng khách để xác thực dựa trên các dịch vụ web. Nó sử dụng một thanh tra thư để chèn tiêu đề cookie. Có một tập tin từ với tài liệu và một dự án demo. Mặc dù nó không chính xác những gì bạn đang làm, nó khá gần. Bạn có thể tải xuống từ here.

1

Trên client sửa đổi < ràng buộc > thẻ của bạn cho dịch vụ (bên <System.ServiceModel>) bao gồm: allowCookies = "true"

Ứng dụng bây giờ sẽ kéo dài cookie và sử dụng nó. Bạn sẽ lưu ý rằng IsLoggedIn hiện trả về true sau khi bạn đăng nhập - nó trả về false nếu bạn không cho phép cookie.

Các vấn đề liên quan