2010-04-06 128 views
14

好的,我很幸運找到針對特定場景的任何文檔或教程。如何在ASP.Net MVC應用程序中使用來自WCF身份驗證服務的身份驗證Cookie

我有一個ASP.Net MVC Web應用程序將使用WCF服務的一切,包括身份驗證和角色(通過WCF後端的成員資格提供程序)。

我已經沒有問題setting up the authentication services但它沒有在網絡應用程序中設置cookie。 Login method of the service的文檔表明可以連接CreatingCookie事件,但它不會對客戶端產生任何影響(我也在服務端嘗試過,也沒有任何影響)。所以我想通了capture the cookie。我嘗試在客戶端上手動設置auth cookie,但到目前爲止它不工作;解密由於填充而失敗,並且設置來自服務器給定的cookie值不能被客戶端讀取。

有誰知道你應該如何使用由WCF身份驗證服務生成的cookie?我是否假設會話全部在WCF服務器上進行管理,並在每次頁面加載時檢查服務上的IsLoggedIn()?

在此先感謝。

+0

閱讀更多關於MSDN的文檔,我想我的場景從未打算由MS;如果你打算在網站上使用會員資格,爲什麼你會認證服務而不是直接打數據庫,所以它看起來像一個網站必須處理相同的任何其他客戶端,這意味着手動抓取cookie從標題和自己使用它們(創建一個委託人,授權票等,並將它們分配給網站的適當部分,以便使用它)。將調查更多,希望有一個答案後... – tap 2010-04-07 04:02:04

回答

11

我最近一直在試圖實現你所描述的相同功能。我設法得到它與下面的代碼工作:

private readonly AuthenticationServiceClient service = new AuthenticationServiceClient(); 

    public void SignIn(string userName, string password, bool createPersistentCookie) 
    { 
     using (new OperationContextScope(service.InnerChannel)) 
     { 
      // login 
      service.Login(userName, password, String.Empty, createPersistentCookie); 

      // Get the response header 
      var responseMessageProperty = (HttpResponseMessageProperty) 
       OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name]; 

      string encryptedCookie = responseMessageProperty.Headers.Get("Set-Cookie"); 

      // parse header to cookie object 
      var cookieJar = new CookieContainer(); 
      cookieJar.SetCookies(new Uri("http://localhost:1062/"), encryptedCookie); 
      Cookie cookie = cookieJar.GetCookies(new Uri("http://localhost:1062/"))[0]; 

      FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value); 
      if (null != ticket) 
      { 
       //string[] roles = RoleManager.GetRolesFromString(ticket.UserData); 
       HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null); 
       FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, createPersistentCookie); 
      } 
     } 
    } 

這不正是你所描述你的問題的評論。

編輯

我在這裏張貼此代碼的服務器端部分以供參考。

public class HttpResponseMessageInspector : BehaviorExtensionElement, IDispatchMessageInspector, IServiceBehavior 
{ 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 

     HttpRequestMessageProperty httpRequest = request.Properties[HttpRequestMessageProperty.Name] 
     as HttpRequestMessageProperty; 

     if (httpRequest != null) 
     { 
      string cookie = httpRequest.Headers[HttpRequestHeader.Cookie]; 

      if (!string.IsNullOrEmpty(cookie)) 
      { 
       FormsAuthentication.Decrypt(cookie); 
       FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookie); 
       string[] roles = PrincipalHelper.GetUserRoles(authTicket); 
       var principal = new BreakpointPrincipal(new BreakpointIdentity(authTicket), roles); 

       HttpContext.Current.User = principal;     
      } 
      // can deny request here 
     } 

     return null; 
    } 
} 
+0

哇,我確實想念一些技巧..讓我看看這是如何工作,我會回到你身邊。無論我真的很感謝你的努力,並感興趣:) – tap 2010-04-13 22:27:46

+0

這表面看起來不錯,但我看到了我遇到的同樣的問題:System.Security.Cryptography.CryptographicException:填充無效,無法刪除。 我對這個錯誤的假設是,由於它是2個不同的上下文(客戶端應用程序和服務應用程序),解密/加密不兼容? 你是如何設置這個起作用的? 再次感謝您的關注和努力:) – tap 2010-04-14 00:18:00

+0

Asp.net MVC和WCF主機應用程序運行在同一臺機器上嗎?如果沒有,則必須將兩個Web.config都設置爲使用相同的機器密鑰。請參閱[http://msdn.microsoft.com/en-us/library/ms998288.aspx] 在我的設置中,MVC和WCF服務主機都在本地計算機上的Visual Studio WebServer中運行。所以機器的關鍵是一樣的。 編輯:也可以嘗試添加此代碼給你WCF主機Global.cs文件明確發送一個cookie只是爲了排除更多的一件事:http://msdn.microsoft.com/en-us/library/bb398778% 28v = VS.100%29.aspx – Karl 2010-04-14 00:42:56

2

這對我的作品...首次設置主機(通過代碼如下所示,但也可以在配置完成)的認證行爲:

ServiceAuthorizationBehavior author = Description.Behaviors.Find<ServiceAuthorizationBehavior>(); 
author.ServiceAuthorizationManager = new FormCookieServiceAuthorizationManager(); 
author.PrincipalPermissionMode = PrincipalPermissionMode.Custom; 
author.ExternalAuthorizationPolicies = new List<IAuthorizationPolicy> { new CustomAuthorizationPolicy() }.AsReadOnly(); 

然後是輔助類

internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager 
    { 
    public override bool CheckAccess(OperationContext operationContext) 
    { 
     ParseFormsCookie(operationContext.RequestContext.RequestMessage); 
     return base.CheckAccess(operationContext); 
    } 
    private static void ParseFormsCookie(Message message) 
    { 
     HttpRequestMessageProperty httpRequest = message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty; 
     if (httpRequest == null) return; 

     string cookie = httpRequest.Headers[HttpRequestHeader.Cookie]; 
     if (string.IsNullOrEmpty(cookie)) return; 

     string regexp = Regex.Escape(FormsAuthentication.FormsCookieName) + "=(?<val>[^;]+)"; 
     var myMatch = Regex.Match(cookie, regexp); 
     if (!myMatch.Success) return; 

     string cookieVal = myMatch.Groups["val"].ToString(); 
     FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookieVal); 
     Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), new string[0]); 
    } 
    } 
    internal class CustomAuthorizationPolicy : IAuthorizationPolicy 
    { 
    static readonly string _id = Guid.NewGuid().ToString(); 
    public string Id 
    { 
     get { return _id; } 
    } 

    public bool Evaluate(EvaluationContext evaluationContext, ref object state) 
    { 
     evaluationContext.Properties["Principal"] = Thread.CurrentPrincipal; 
     evaluationContext.Properties["Identities"] = new List<IIdentity> { Thread.CurrentPrincipal.Identity }; 
     return true; 
    } 

    public ClaimSet Issuer 
    { 
     get { return ClaimSet.System; } 
    } 
    } 

以及當AspNetCompatibility設置,然後FormCookieServiceAuthorizationManager稍微簡單:

internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager 
{ 
    public override bool CheckAccess(OperationContext operationContext) 
    { 
     Thread.CurrentPrincipal = HttpContext.Current.User; 
     return base.CheckAccess(operationContext); 
    } 
}