现在的位置: 首页 > 综合 > 正文

为SharePoint 2010中的FBA创建自定义登录页面

2011年04月10日 ⁄ 综合 ⁄ 共 6941字 ⁄ 字号 评论关闭

为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官方支持,如果你要用在你的项目中,风险自负。Smile

创建自定义登录页面

如果我们留意一下会发现,默认的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目录里。当执行登录时,如果用户没有输入正确的验证码,下面的错误会显示出来。

这个登录页面的代码可以从这里下载

【上篇】
【下篇】

抱歉!评论已关闭.