為SharePoint 2010中的FBA創建自定義登錄頁面
SharePoint 2010中默認的FBA登錄頁面非常簡單,只提供了一個Asp.Net的Login控件,讓用戶輸入用戶名和密碼。在大多數情況下,我們需要定制這個頁面以滿足一些安全需求,比如為登錄頁面加上驗證碼等等。
由于SharePoint 2010里的FBA已經變成了基于Claims認證的方式,因此在實現自定義的登錄頁面時就與MOSS 2007里的做法完全不同了。最顯著的一點就是,像Steve Peschka說的,以前的FormsAuthentication類不會再被用到了。現在我們需要用SharePoint的STS來做認證和處理Claims。好在SharePoint提供了相應的借口,讓這一切變得容易了許多。這這篇文章里,我將演示如何創建自定義登錄頁面,并保持默認的master page和樣式。
由于要修改默認頁面,我不知道這樣的做法是否受Microsoft官方支持,如果你要用在你的項目中,風險自負。![]()
創建自定義登錄頁面
如果我們留意一下會發現,默認的FBA登錄頁面是_forms/default.aspx。這樣的設計有一個好處,就是如果我們修改了default.aspx,它不會影響別的Web app。下面我就在一個default.aspx頁面上加了一個驗證碼功能。
<asp:login id="loginControl"
FailureText="<%$Resources:wss,login_pageFailureText%>"
runat="server" width="100%" OnLoggingIn="signInControl_LoggingIn"
OnAuthenticate="signInControl_Authenticate"> <layouttemplate>
<asp:label id="FailureText" class="ms-error" runat="server"/>
<table width="100%">
<tr>
<td nowrap="nowrap">
<SharePoint:EncodedLiteral runat="server"
text="<%$Resources:wss,login_pageUserName%>"
EncodeMethod='HtmlEncode'/>
</td>
<td width="100%">
<asp:textbox id="UserName"
autocomplete="off"
runat="server"
class="ms-inputuserfield" width="99%" />
</td>
</tr>
<tr>
<td nowrap="nowrap">
<SharePoint:EncodedLiteral runat="server"
text="<%$Resources:wss,login_pagePassword%>"
EncodeMethod='HtmlEncode'/>
</td>
<td width="100%">
<asp:textbox id="password" TextMode="Password"
autocomplete="off" runat="server"
class="ms-inputuserfield" width="99%"/>
</td>
</tr>
<tr>
<td nowrap="nowrap">
<SharePoint:EncodedLiteral runat="server"
text="Secure Code:" EncodeMethod='HtmlEncode'/>
</td>
<td width="100%">
<asp:textbox id="secureCode" autocomplete="off"
runat="server" class="ms-inputuserfield" Width="85%" />
<SharePoint:EncodedLiteral ID="secureCodeLit"
runat="server" Text="1234" EncodeMethod="HtmlEncode" />
</td>
</tr>
<tr>
<td colspan="2" align="right">
<asp:button id="login" commandname="Login"
text="<%$Resources:wss,login_pagetitle%>" runat="server" />
</td>
</tr>
<tr>
<td colspan="2">
<asp:checkbox id="RememberMe"
text="<%$SPHtmlEncodedResources:wss,login_pageRememberMe%>"
runat="server" />
</td>
</tr>
</table>
</layouttemplate>
</asp:login>
我的想法是,當用戶登錄的時候,只有輸入了正確的用戶名密碼和驗證碼,這里是1234,之后才能成功登錄。頁面運行的效果如下:

當然,此時驗證碼還沒有作用,我們必須寫一些代碼來實現驗證的功能。
創建Code Behind類實現驗證和登錄功能
接下來是為default.aspx實現一個類來實現驗證和登錄功能。在項目中添加一個類,可以命名為FormsSignInPage。接著是添加一些引用,首先是Microsoft.SharePoint.dll。由于我們要處理Claims,System.IdentityModel.dll和Microsoft.IdentityModel.dll也是必須的。另外,SharePoint有一個自己的處理Claims的Module,Microsoft.SharePoint.IdentityModel.dll。添加對它的引用時,需要定位到它所在的目錄。引用添加完,看起來像下面這樣。

我們的類,FormsSignInPage,當然可以從Asp.Net的Page類派生,但是如果我們看一下默認的登錄頁面,它是派生自IdentityModelSignInPageBase。這個類在Microsoft.SharePoint.IdentityModel.Pages名字空間下,它提供了一些屬性和方法,在處理登錄時很方便。所以,我決定我的FormsSignInPage也從這個類派生。
當用戶點擊頁面上的登錄按鈕時,有兩個Login控件的事件需要處理,一個是LoggingIn,在這個事件中,我們可以處理驗證碼。另一個是Authenticate,在這個事件中可以實現真正的登錄。
protected void signInControl_LoggingIn(objectsender, LoginCancelEventArgs e)
{
LoginControl login = sender asLoginControl;
login.UserName = login.UserName.Trim();
if(string.IsNullOrEmpty(login.UserName))
{
ClaimsFormsPageMessage.Text = "The server could not sign you in. The user name cannot be empty.";
e.Cancel = true;
}
if(string.IsNullOrEmpty(secureCode.Text) ||
!string.Equals(secureCode.Text.ToLower(), secureCodeLit.Text.ToLower()))
{
ClaimsFormsPageMessage.Text = "The server could not sign you in. Please input correct secure code.";
e.Cancel = true;
}
}
private void EstablishSessionWithToken(SecurityToken securityToken)
{
if (null == securityToken)
{
throw new ArgumentNullException("securityToken");
}
SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current;
if (null == fam)
{
throw new ArgumentException(null, "FederationAuthenticationModule");
}
fam.SetPrincipalAndWriteSessionToken(securityToken);
}
protected void signInControl_Authenticate(object sender, AuthenticateEventArgs e)
{
SecurityToken token = null;
LoginControl formsLoginControl = sender as LoginControl;
if (null != (token = GetSecurityToken(formsLoginControl)))
{
EstablishSessionWithToken(token);
e.Authenticated = true;
base.RedirectToSuccessUrl();
}
}
private SPIisSettings IisSettings
{
get
{
SPWebApplication webApp = SPWebApplication.Lookup(new Uri(SPContext.Current.Web.Url));
SPIisSettings settings = webApp.IisSettings[SPUrlZone.Default];
return settings;
}
}
private SecurityToken GetSecurityToken(LoginControl formsLoginControl)
{
SecurityToken token = null;
SPIisSettings iisSettings = IisSettings;
Uri appliesTo = base.AppliesTo;
if (string.IsNullOrEmpty(formsLoginControl.UserName) ||
string.IsNullOrEmpty(formsLoginControl.Password))
return null;
SPFormsAuthenticationProvider authProvider = iisSettings.FormsClaimsAuthenticationProvider;
token = SPSecurityContext.SecurityTokenForFormsAuthentication(
appliesTo,
authProvider.MembershipProvider,
authProvider.RoleProvider,
formsLoginControl.UserName,
formsLoginControl.Password);
return token;
}
代碼的核心部分是執行登錄的部分。SharePoint提供了SecurityTokenForFormsAuthentication專門供開發者處理Forms驗證。我使用了SPIisSettings來取得當前Web App所使用的membership provider和roleship provider。
SPFormsAuthenticationProvider authProvider = iisSettings.FormsClaimsAuthenticationProvider;
token = SPSecurityContext.SecurityTokenForFormsAuthentication(
appliesTo,
authProvider.MembershipProvider,
authProvider.RoleProvider,
formsLoginControl.UserName,
formsLoginControl.Password);
關聯Default.aspx和FormsSignInPage
這部分比較簡單,只要修改<%@ Page %>使它繼承我們的FormsSignInPage就好了。
<%@PageLanguage="C#"AutoEventWireup="true"
Inherits="Morpheus.Demo.Pages.FormsSignInPage,FormsSignInPage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=72d2bbe72853b8eb"
MasterPageFile="~/_layouts/simple.master"%>
然后我們就可以將我們的Assembly部署到GAC中,同時將default.aspx拷貝到_forms目錄里。當執行登錄時,如果用戶沒有輸入正確的驗證碼,下面的錯誤會顯示出來。
浙公網安備 33010602011771號