摘要
如果您使用的自定义身份验证机制不以 Windows 帐户为基础,那么要在 Web 应用程序中使用基于 Microsoft .NET 角色的安全性,您必须直接负责创建 ASP.NET 身份验证票和配置 IPrincipal 实例。这些身份验证票代表经过身份验证的用户的标识和角色。
本模块描述了如何创建一个使用 Forms 身份验证对用户进行身份验证的 Web 应用程序,以及如何创建一个包含用户和角色信息的身份验证票。它还说明了如何将此信息映射到 GenericPrincipal 和 FormsIdentity 对象,以便使这些对象可用于应用程序内的授权逻辑。
预备知识
使用 Forms 身份验证的应用程序通常要使用 GenericPrincipal 类(与 FormsIdentity 类结合使用)来创建一个独立于 Windows 域的非 Windows 的特定授权方案。
例如,应用程序可以:
• |
使用 Forms 身份验证来获得用户凭据(用户名和密码)。 |
• |
根据数据存储验证提供的凭据;例如,数据库或 Microsoft Active Directory® 目录服务。 |
• |
根据从数据存储中检索到的值创建 GenericPrincipal 和 FormsIdentity 对象。这些对象可能包含用户的角色成员关系详细信息。 |
• |
使用这些对象作出授权决策。 |
本模块描述了如何创建一个基于 Forms 的 Web 应用程序,此程序对用户进行身份验证并创建一个包含用户和角色信息的自定义 Forms 身份验证票。它还说明了如何将此信息映射到 GenericPrincipal 和 FormsIdentity 对象,并将新对象与 HTTP Web 请求上下文关联起来,以便使这些对象可用于应用程序内的授权逻辑。
本模块主要介绍 GenericPrincipal 对象和 FormsIdentity 对象的构造,同时也讲述了对 forms 身份验证票的处理。有关如何根据 Active Directory 和 SQL Server 2000 对用户进行身份验证的详细信息,请参阅本指南中的下列相关模块:
• | |
• |
创建一个有登录页的 Web 应用程序
此过程创建一个新的 ASP.NET Web 应用程序。此应用程序将包含两个页;一个是只允许经过身份验证的用户访问的默认页,另一个是用于收集用户凭据的登录页。
要创建一个有登录页的 Web 应用程序,请执行下列操作:
1. |
启动 Visual Studio .NET 并创建一个名为 GenericPrincipalApp 的新 Visual C# ASP.NET Web 应用程序。 |
2. |
将 WebForm1.aspx 重命名为 Logon.aspx。 |
3. |
将下列控件添加到 Logon.aspx 来创建登录窗体。 |
表 1:Logon.aspx 控件 | ||
控件类型 | 文本 | ID |
Label |
User Name: |
- |
Label |
Password |
- |
Text Box |
- |
txtUserName |
Text Box |
- |
txtPassword |
Button |
Logon |
btnLogon |
1. |
将密码文本框控件的 TextMode 属性设置为 Password。 |
2. |
在解决方案资源管理器中,右键单击 GenericPrincipalApp,指向 Add,然后单击 Add Web Form。 |
3. |
输入 default.aspx 作为新窗体的名称,然后单击 Open 。 |
配置 Web 应用程序进行 Forms 身份验证
要通过编辑应用程序的 Web.config 文件来配置应用程序进行 Forms 身份验证,请执行下列操作:
1. |
使用解决方案资源管理器打开 Web.config。 |
2. |
定位到 <authentication> 元素并将 mode 属性更改为 Forms。 |
3. |
将下列 <forms> 元素作为 <authentication> 元素的子元素进行添加,并设置 loginUrl、name、timeout 和 path 属性,如下所示: |
4. |
将下列 <authorization> 元素添加到 <authentication> 元素下。执行这一步的目的是只允许经过身份验证的用户访问应用程序。前面建立的 <authentication> 元素的 loginUrl 属性将未经过身份验证的请求重定向到 Logon.aspx 页。 |
为经过身份验证的用户生成身份验证票
此过程编写代码来为经过身份验证的用户生成身份验证票。身份验证票是由 ASP.NET FormsAuthenticationModule 使用的一种 cookie。
身份认证代码通常涉及到根据自定义数据库或 Active Directory 查找所提供的用户名和密码。
有关执行这些查找的详细信息,请参阅本指南中的下列模块:
• | |
• |
要为经过身份验证的用户生成身份验证票,请执行下列操作:
1. |
打开 Logon.aspx.cs 文件并将下列 using 语句添加到位于文件顶部的现有 using 语句下: using System.Web.Security; |
2. |
将下列私有 Helper 方法添加到名为 IsAuthenticated 的 WebForm1 类中,此类用于验证用户名和密码来对用户进行身份验证。此代码假定所有用户名和密码组合都是有效的。 private bool IsAuthenticated( string username, string password ) { // Lookup code omitted for clarity // This code would typically validate the user name and password // combination against a SQL database or Active Directory // Simulate an authenticated user return true; } |
3. |
添加下列名为 GetRoles 的私有 Helper 方法,此方法用于获得用户所属的角色的集合。 private string GetRoles( string username, string password ) { // Lookup code omitted for clarity // This code would typically look up the role list from a database table. // If the user was being authenticated against Active Directory, the // Security groups and/or distribution lists that the user belongs to may be // used instead // This GetRoles method returns a pipe delimited string containing roles // rather than returning an array, because the string format is convenient // for storing in the authentication ticket / cookie, as user data return "Senior Manager|Manager|Employee"; } |
4. |
在 Designer 模式下显示 Logon.aspx 窗体并双击 Logon 按钮创建一个单击事件处理程序。 |
5. |
添加一个对 IsAuthenticated 方法的调用,提供通过登录窗体捕获的用户名和密码。将返回值赋给一个 bool 类型的变量,此变量指出用户是否已经过身份验证。 bool isAuthenticated = IsAuthenticated( txtUserName.Text, txtPassword.Text ); |
6. |
如果用户已经过身份验证,则添加对 GetRoles 方法的调用来获得用户的角色列表。 if (isAuthenticated == true ) { string roles = GetRoles( txtUserName.Text, txtPassword.Text ); |
7. |
创建一个包含用户名、截止时间和用户所属的角色列表的新窗体身份验证票。注意,身份验证票的用户数据属性用于存储用户的角色列表。还要注意,虽然票 /cookie 是否是永久性的取决于您采用的应用程序方案,但下列代码会创建一个非永久性票。 // Create the authentication ticket FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, // version txtUserName.Text, // user name DateTime.Now, // creation DateTime.Now.AddMinutes(60),// Expiration false, // Persistent roles ); // User data |
8. |
添加代码来创建票的加密字符串表示形式,并将其作为数据存储在 HttpCookie 对象中。 // Now encrypt the ticket. string encryptedTicket = FormsAuthentication.Encrypt(authTicket); // Create a cookie and add the encrypted ticket to the // cookie as data. HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); |
9. |
将此 cookie 添加到返回给用户浏览器的 cookie 集合中。 // Add the cookie to the outgoing cookies collection. Response.Cookies.Add(authCookie); |
10. |
将用户重定向到最初请求的页。 // Redirect the user to the originally requested page Response.Redirect( FormsAuthentication.GetRedirectUrl( txtUserName.Text, false )); } |
构造 GenericPrincipal 和 FormsIdentity 对象
此过程实现了一个应用程序身份验证事件处理程序,并根据身份验证票中包含的信息构造了 GenericPrincipal 和 FormsIdentity 对象。
要构造 GenericPrincipal 和 FormsIdentity 对象,请执行下列操作:
1. |
从解决方案资源管理器中,打开 global.asax。 |
2. |
切换到代码视图并将下列 using 语句添加到文件顶部: using System.Web.Security; using System.Security.Principal; |
3. |
定位到 Application_AuthenticateRequest 事件处理程序并添加下列代码,以从随请求传递的 cookie 集合中获得窗体身份验证 cookie。 // Extract the forms authentication cookie string cookieName = FormsAuthentication.FormsCookieName; HttpCookie authCookie = Context.Request.Cookies[cookieName]; if(null == authCookie) { // There is no authentication cookie. return; } |
4. |
添加下列代码以从窗体身份验证 cookie 中提取和解密身份验证票。 FormsAuthenticationTicket authTicket = null; try { authTicket = FormsAuthentication.Decrypt(authCookie.Value); } catch(Exception ex) { // Log exception details (omitted for simplicity) return; } if (null == authTicket) { // Cookie failed to decrypt. return; } |
5. |
添加下列代码,以便解析出用户在最初对用户进行身份验证时附加到票上的管道分隔的角色名称列表。 // When the ticket was created, the UserData property was assigned a // pipe delimited string of role names. string[] roles = authTicket.UserData.Split(new char[]{'|'}); |
6. |
添加下列代码来创建一个 FormsIdentity 对象和一个 GenericPrincipal 对象。前一个对象从票名称获得用户名,后一个对象将此标识与用户角色列表包含在一起。 // Create an Identity object FormsIdentity id = new FormsIdentity( authTicket ); // This principal will flow throughout the request. GenericPrincipal principal = new GenericPrincipal(id, roles); // Attach the new principal object to the current HttpContext object Context.User = principal; |
测试应用程序
此过程将代码添加到 default.aspx 页以显示已附加到当前 HttpContext 对象的 GenericPrincipal 对象中的信息,目的是确认此对象是否已正确构造且分配给当前的 Web 请求。然后,可以生成并测试此应用程序。
要测试应用程序,请执行下列操作:
1. |
在解决方案资源管理器中,双击 default.aspx。 |
2. |
双击 default.aspx Web 窗体来显示页加载事件处理程序。 |
3. |
滚动到文件顶部并将下列 using 语句添加到现有 using 语句下。 using System.Security.Principal; |
4. |
返回到页加载事件处理程序并添加下列代码,以显示附加到与当前 Web 请求关联的 GenericPrincipal 的标识名称。 IPrincipal p = HttpContext.Current.User; Response.Write( "Authenticated Identity is: " + p.Identity.Name ); Response.Write( " |
5. |
添加下列代码以测试当前经过身份验证的标识的角色成员关系。 if ( p.IsInRole("Senior Manager") ) Response.Write( "User is in Senior Manager role |
6. |
在解决方案资源管理器中,右键单击 default.aspx,然后单击 Set As Start Page。 |
7. |
在 Build 菜单上,单击 Build Solution。消除任何生成错误。 |
8. |
按 Ctrl+F5 运行此应用程序。由于 default.aspx 被配置为启动页,所以这是最初请求的页。 |
9. |
当您被重定向到登录页时(因为最初您没有身份验证票),输入用户名和密码(可随意输入),然后单击 Logon。 |
10. |
确认您被重定向到 default.aspx 且显示了用户标识和正确的角色详细信息。用户应为 Senior Manager、Manager 和 Employee 角色的成员,但不是 Sales 角色的成员。 |
其他资源
有关详细信息,请参阅本指南中的下列相关模块:
• | |
• |