2009-07-05 193 views
10

背景與WCF服務

身份驗證ASP.NET Web應用程序我有與WCF服務交互的ASP.NET Web應用程序。 Web應用程序和WCF服務在我的控制之下。 ASP.NET Web應用程序使用ASP.NET成員資格提供程序模型(密碼以散列形式存儲)的自定義實現來對登錄到Web應用程序的用戶進行身份驗證。 ASP.NET Web應用程序和WCF服務都可以訪問相同的成員資格數據庫。

由於用戶只會提供一次密碼,我不希望將密碼存儲在任何地方,或者通過反覆要求重新提供密碼來惹惱他們,我需要一個適當的機制來驗證用戶身份WCF服務。

根據我所看到的其他問題和答案,我正在考慮一種「登錄會話」方式,其中在用戶最初登錄到Web應用程序時將在自定義成員資格數據庫中創建登錄會話,由GUID標識的登錄會話,並在一段時間不活動後自動過期。登錄會話GUID將由Web應用程序爲每個登錄用戶「記憶」(存儲在Forms Authentication Ticket或會話中)。

WCF服務還將提供自己的登錄操作,接受用戶名和密碼並返回登錄會話GUID,如上所述。

然後,WCF服務將接受所有其他操作的登錄會話GUID,並驗證GUID是否表示允許繼續操作之前未過期的有效登錄會話。

我已經做了相當多的背景閱讀,並且有很多關於直接使用UserName客戶端憑證類型的資料,但是這需要Web應用程序記住用戶的密碼,而不是對我來說似乎是個好主意。

我已經做了一些研究,並在MSDN上找到了材料,但是這似乎需要很多努力才能實現(對我來說至少)似乎是一個非常常見的使用場景。

How to: Create a Custom Token

問題

以上是合理的描述的 「登錄會話」 的一般方法?
如果是這樣,那麼實現它的最好方法是什麼?
如果不是,你可以提出一個替代方案嗎?

+0

您的WCF服務只能從內部網絡訪問嗎?如果是這樣的話,我不認爲需要重新認證請求。 – 2009-07-05 22:07:17

+0

對不起 - WCF服務將在互聯網上提供。 – 2009-07-06 05:50:30

回答

1

感謝大家的意見。我已經解決了一個方法(至少現在)。它非常簡單,適用於我的目的。

使用「用戶名」clientCredentialType和返回安全令牌的顯式服務登錄方法(爲簡潔起見省略了令牌生成詳細信息),服務客戶端可以決定是否將正版密碼作爲密碼屬性傳遞給客戶端憑證或者安全令牌(取自登錄方法)。如果客戶端是Web應用程序,則安全令牌可以存儲在表單身份驗證票證或會話中或任何地方。

使用「自定義」 userNamePasswordValidationMode和UserNamePasswordValidator的自定義實現,驗證檢查密碼,以確定它是否是一個有效的安全令牌或密碼 - 如果它是一個密碼,客戶證書是針對用戶存儲認證(SQL服務器數據庫),如果它是一個安全令牌,那麼會檢查它是否有效,是否已過期並屬於用戶名。

1

有兩種可能的解決方案,我能想到的:

首先,如果WCF服務是內部服務,Web應用程序可以發送被要求與每個請求數據的用戶名。

第二個是你在某處存儲用戶名和密碼(或實際密碼)的散列。無論是在會話狀態還是在用戶cookie中(會話cookie存儲在通過https傳遞給用戶的內存中)。然後將每個請求傳遞給WCF服務的用戶名和密碼。

+1

WCF服務將在互聯網上提供。 如果我存儲密碼的哈希值,那麼我需要使用密碼的哈希來啓用WCF服務的身份驗證 - 據我所見,這實際上使得它只是一個密碼(儘管一個會很難/不可能猜測),但如果受到威脅(至少在用戶更改密碼之前)仍然是「永久」有用的東西。 我最初描述的使用登錄會話令牌方法意味着登錄會話令牌只在短時間內有效,如果受到威脅,風險將小得多。 – 2009-07-06 07:25:38

1

有關不需要存儲密碼的解決方案,請參閱我在Storing password in forms authentication cookie - ASP.NET and WCF calls上的回答。

+0

在發佈此問題之前,我已閱讀過您參考的答案。這聽起來像一個有趣的方法,但我對機制有點朦朧。你能否澄清或提供一個例子? – 2009-07-08 19:50:54

+0

@Secret Squirrel,我在另一頁面擴展了答案。 – 2009-07-09 05:30:42

2

這是一個非常合理的方法。

要做到這一點,你設置你的服務端點,並與您的自定義成員資格提供配置它(你可以做SQL成員資格提供相同的,它不需要一個自定義)。

您設置的登錄控制的Authenticate事件實例化一個新的服務代理並在代理ClientCredentials設置的用戶名/密碼的Web應用程序。

現在,當你撥打電話通過代理WCF服務將通過安全通道將這些憑據傳遞給服務,並利用它們進行身份驗證。

現在你只需要存儲的代理會話,並將其用於未來的訪問服務,因爲它具有信道狀態和私鑰。

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e) 
{ 
    bool Authenticated = false; 
    try 
    { 
     MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint"); 
     proxy.ClientCredentials.UserName.UserName = LoginControl.UserName; 
     proxy.ClientCredentials.UserName.Password = LoginControl.Password; 

     //It doesn't really matter what is called or what it does because 
     //Membership Provider for the Service does the authentication. 
     string retval = proxy.login("Logging in"); 

     //Now that channel is established the proxy needs to be kept 
     //since it contains the channel state which includes a private key 
     Session["MyServiceProxy"] = proxy; 
     Authenticated = true; 
    } 
    catch (Exception ex) 
    { 
     //Login Error... 
    } 
    e.Authenticated = Authenticated; 
} 
0

我建議看看Geneva,它的目的是爲了解決你的情況。基本的想法是爲WCF服務和ASP站點要求相同的安全令牌(通過HttpModule)。該令牌將在對您的會員資格數據庫進行身份驗證後發佈,並可能包含用戶的有用信息(聲明)。

對於介紹,您可能會讀取Bustamante's article