[索引页]
[×××]



温故知新ASP.NET 2.0(C#)(6) - Membership&RoleManager(成员资格和角色管理)


作者: webabcd


介绍
现在 ASP.NET 2.0 提供了对成员资格(用户名/密码凭据存储)和角色管理服务的内置支持。由于所有这些服务都是提供程序驱动的(Provider),因此可以方便地用您自己的自定义实现替换。


关键
1、基于Windows的身份验证将<system.web>元素下的<authentication> 设置为 Windows;基于Forms的身份验证将<system.web>元素下的<authentication> 设置为 Forms。

2、基于Forms的身份验证时,设置<system.web>元素下的<authentication> 元素的 <forms> 子元素,示例如下,仅为说明
<authentication mode="Forms">

            <forms name=".VS2005_Form" loginUrl="~/Security/Login.aspx" defaultUrl="~/Default.aspx"
                    protection="All" timeout="30" path="/" requireSSL="false"
                    slidingExpiration="true" enableCrossAppRedirects="false"
                    cookieless="UseDeviceProfile">
            </forms>

        </authentication>
 
<forms>元素的属性说明如下
1) cookieless - 身份验证可以将 Forms 身份验证票存储在 Cookie 中也可以以无 Cookie 的表示形式存储在 URL 上。有效值如下:
  ·UseDeviceProfile - 默认值表示 ASP.NET 根据预先计算得到的浏览器配置文件来确定存储票证的位置。
  ·AutoDetect - 选项使 ASP.NET 动态确定浏览器是否支持 Cookie。
  ·UseUri - 强制实施无 Cookie 票证 
  ·UseCookies - 强制实施有 Cookie 票证。
2) defaultUrl - 指定在成功登录后,请求将重定向到的默认 URL。
3) domain - 指定包含 Forms 身份验证票的 HttpCookie 的 Domain 属性的值。显式设置此属性可使应用程序共享同一个 Cookie,前提是这些应用程序共享某个 DNS 命名空间的一个公共部分(例如,如果 domain 属性设置为“cnblogs.com”,则 webabcd.cnblogs.com 和 dudu.cnblogs.com可以共享一个 Cookie)。
4) enableCrossAppRedirects - Forms 身份验证允许以查询字符串变量或窗体 POST 变量的形式在应用程序之间传递 Forms身份验证票。将此属性设置为 true 可使 FormsAuthenticationModule 能够从查询字符串或窗体 POST 变量提取票证。
5) loginUrl - 指定未经身份验证的用户的请求将被重定向到的 URL。该 URL 可以在同一台计算机上或在远程计算机上。如果是在远程计算机上,则两台计算机上 machineKey 配置元素中的 decryptionkey 和 validationKey 属性都需要使用相同的值。
6) name - 用于身份验证的 HTTP Cookie 的名称。注意,如果多个应用程序需要在一台计算机上使用基于窗体的身份验证服务,并且每个应用程序都希望由应用程序隔离 Forms 身份验证 Cookie,则每个应用程序都应配置一个唯一的 Cookie 值。为避免在 URL 中产生依赖项,在设置身份验证 Cookie 时,ASP.NET 还使用“/”作为 Path 值,以便将这些 Cookie 发送回站点上的每个应用程序。
7) path - 用于发出的 Cookie 的路径。默认值为“/”,以避免路径中大小写不匹配的造成的困难,因为在返回 Cookie 时,浏览器是严格区分大小写的。共享服务器环境中的应用程序应使用此指令来维护专用 Cookie。(它们还可以使用 API 在运行时指定路径来发出 Cookie。) 
8) protection - 用于保护 Cookie 数据的方法。有效值如下: 
  ·All - 同时使用数据验证和加密来保护 Cookie。所配置的数据验证算法是基于 <machinekey> 元素的。如果密钥足够长(48 个字符),默认情况下将使用 AES 进行加密。All 是默认(和建议)值。 
  ·None - 用于仅将 Cookie 用于个性化设置并且安全性要求不高的站点。加密和验证都可以被禁用。尽管以此方式使用 Cookie 需谨慎,但对于使用 .NET Framework 实现个性化设置的任何方法,此设置提供了最佳性能。 
  ·Encryption - 使用 AES、TripleDES 或 DES 加密 Cookie,但不对 Cookie 进行数据验证。这类 Cookie 容易受到精心选择的纯文本的***。
  ·Validation - 不加密 Cookie 的内容,但验证 Cookie 数据在传输过程中是否未被更改。若要创建 Cookie,验证密钥在缓冲区中与 Cookie 数据连接,并且计算出 MAC 并将其追加到输出的 Cookie。 
9) requireSSL - 如果设置为 true,则 Forms 身份验证会设置 Forms 身份验证 Cookie 的安全位。兼容的浏览器只将 Cookie 通过 SSL 连接发送回 ASP.NET。注意,如果使用无 Cookie Forms 身份验证,则此设置无效。 
10) slidingExpiration - 如果设置为 true,则 Forms 身份验证将定期更新 Forms 身份验证票的生存期。无论票证是包含在 Cookie 中,还是以无 Cookie 的格式包含在 URL 中,都会进行此操作。 
11) timeout - 时间量(以整数分钟为单位),经过该时间量之后,Cookie 则会过期。默认值是 30。超时属性是一个可调值,从收到上次请求的时间开始计算,它将在 n 分钟后过期。为了避免对性能产生负面影响,也为了避免那些打开了 Cookie 警告的应用程序产生多个浏览器警告,Cookie 在超时时间过半时更新。(这意味着在某些情况下可能会出现精度损失。) (注意:createPersistentCookie为true的话,则该属性失效,过期时间将为50年)

3、授权用户和角色设置<system.web>元素下的<authorization>元素,示例如下,仅为说明
<authorization>
        <allow VERB="POST" users="webabcd@gmail.com" />
        <allow roles="admin" />
        <deny users="*" />
        <allow VERB="GET" users="abc,xyz" />
        <deny users="?" />
</authorization>
注:可以把授权用户和角色设置的配置写在某个文件夹内,则所做的配置只作用于该文件夹内,自动继承外面的配置。
allow - 允许
deny - 拒绝
users - 用户(多用户用逗号隔开)
roles - 角色(多角色用逗号隔开)
verb - 指定http方法,post或get
* - 所有用户
? - 匿名(未经过身份验证的)用户

4、分路径设置授权用户和角色设置,示例如下,仅为说明
<location path="folder">
                <system.web>
                        <authorization>
                                <deny users="?"/>
                                <allow users="*"/>
                        </authorization>
                </system.web>
        </location>
        
        <location path="abc.aspx">
                <system.web>
                        <authorization>
                                <allow roles="Administrators" />
                                <deny users="*"/>
                        </authorization>
                </system.web>
        </location>
<location>元素的path属性可以是文件夹也可以是某一文件

5、<membership>元素设置,示例如下,仅为说明
<membership defaultProvider="SqlMembershipProvider">
            <providers>
                <clear/>
                <add name="SqlMembershipProvider"
                         type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
                         connectionStringName="SqlConnectionString"
                         enablePasswordRetrieval="false"
                         enablePasswordReset="true"
                         requiresQuestionAndAnswer="false"
                         applicationName="/"
                         requiresUniqueEmail="false"
                         passwordFormat="Hashed"
                         maxInvalidPasswordAttempts="3"
                         minRequiredPasswordLength="3"
                         minRequiredNonalphanumericCharacters="0"
                         passwordAttemptWindow="10"
                         passwordStrengthRegularExpression="" />
            </providers>
        </membership>
 
enablePasswordRetrieval - 是否可以检索用户密码(总是false)
enablePasswordReset - 是否允许用户重置其密码
requiresQuestionAndAnswer - 是否要求在创建用户时提供密码提示问题和答案
applicationName - 自定义成员资格提供程序的应用程序的名称
requiresUniqueEmail - 电子邮件地址是否必须是唯一的
passwordFormat - 存储的密码的格式
maxInvalidPasswordAttempts - 指定允许的无效密码或无效密码提示问题答案尝试的次数。当无效尝试的次数达到配置的值时,将锁定该成员资格用户
minRequiredPasswordLength - 密码所要求的最小长度
minRequiredNonalphanumericCharacters - 有效密码中必须包含的最少特殊字符数
passwordAttemptWindow - 跟踪失败的尝试所用的时间(以分钟为单位)。每当发生另一次失败时都将重置窗口。如果达到了允许的无效密码或密码提示问题答案的最大尝试次数,将锁定成员资格用户
passwordStrengthRegularExpression - 用于验证密码的正则表达式

6、<roleManager>元素设置,示例如下,仅为说明
<roleManager defaultProvider="SqlRoleProvider"
            enabled="true"
            cacheRolesInCookie="true"
            cookieName=".VS2005_Role"
            cookieTimeout="30"
            cookiePath="/"
            cookieRequireSSL="false"
            cookieSlidingExpiration="true"
            cookieProtection="All">
            <providers>
                <add
                    name="SqlRoleProvider"
                    type="System.Web.Security.SqlRoleProvider"
                    connectionStringName="SqlConnectionString"
                    applicationName="/" />
            </providers>
        </roleManager>
 
各属性详细说明参看MSDN,索引处查找“roleManager 元素”

7、使用加密密码
<authentication>
        <credentials passwordFormat="SHA1" >
                <user name="Mary" password="94F85995C7492EEC546C321821AA4BECA9A3E2B1"/>
                <user name="John" password="5753A498F025464D72E088A9D5D6E872592D5F91"/>
        </credentials>
</authentication>
 
使用FormsAuthentication.HashPasswordForStoringInConfigFile(String password, String passwordFormat)生成密码
Clear - 密码以明文形式存储 
SHA1 - 密码存储为 SHA1 摘要 
MD5 - 密码存储为 MD5 摘要 

8、使用用户帐户模拟,在<system.web>元素下加如下元素
<identity impersonate="true" username="" password="" />
 
9、常用的就是如下这些东东
System.Web.Security.Membership,System.Web.Security.MembershipUser,System.Web.Security.Roles,Page.User
FormsAuthentication.RedirectFromLoginPage,FormsAuthentication.SetAuthCookie,FormsAuthentication.SignOut
重写那些Provider的话,参看源码中微软提供的示例


示例
读取用户名和验证类型
Security/Test.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Test.aspx.cs"
        Inherits="Security_Test" Title="读取用户名和验证类型" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <p>
                用户名称:
                <%=User.Identity.Name %>
                <br />
                验证类型:
                <%=User.Identity.AuthenticationType %>
        </p>
</asp:Content>
 
Membership测试
App_Code/User.cs
InBlock.gif using System;
InBlock.gif using System.Data;
InBlock.gif using System.Configuration;
InBlock.gif using System.Web;
InBlock.gif using System.Web.Security;
InBlock.gif using System.Web.UI;
InBlock.gif using System.Web.UI.WebControls;
InBlock.gif using System.Web.UI.WebControls.WebParts;
InBlock.gif using System.Web.UI.HtmlControls;
InBlock.gif
InBlock.gif using System.ComponentModel;
InBlock.gif
/// <summary>
/// User 的摘要说明
/// </summary>
InBlock.gif[DataObject( true)]
InBlock.gif public class User
InBlock.gif{
InBlock.gif         public User()
InBlock.gif        {
InBlock.gif                 //
InBlock.gif                 // TODO: 在此处添加构造函数逻辑
InBlock.gif                 //
InBlock.gif        }
InBlock.gif
InBlock.gif         /// <summary>
InBlock.gif         /// 获得所有用户
InBlock.gif         /// </summary>
InBlock.gif         /// <returns></returns>
InBlock.gif        [DataObjectMethod(DataObjectMethodType.Select, true)]
InBlock.gif         public MembershipUserCollection GetMembers()
InBlock.gif        {
InBlock.gif                MembershipUserCollection muc = Membership.GetAllUsers();
InBlock.gif                 return muc;
InBlock.gif        }
InBlock.gif
InBlock.gif         /// <summary>
InBlock.gif         /// 删除用户
InBlock.gif         /// </summary>
InBlock.gif         /// <returns></returns>
InBlock.gif        [DataObjectMethod(DataObjectMethodType.Delete, true)]
InBlock.gif         public void DeleteMember( string username)
InBlock.gif        {
InBlock.gif                Membership.DeleteUser(username, true);
InBlock.gif        }
InBlock.gif}
 
Security/User.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="User.aspx.cs"
        Inherits="Security_User" Title="Membership测试" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <p>
                <asp:Label ID="lblMsg" runat="Server" ForeColor="red" />
        </p>
        <p>
                用户名:
                <asp:TextBox ID="txtUsername" runat="server"></asp:TextBox>
        </p>
        <p>
                密    码:
                <asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
        </p>
        <p>
                <asp:Button ID="btnSubmit" runat="server" Text="添加" OnClick="btnSubmit_Click" />
        </p>
        <p>
                <asp:GridView ID="GridView1" runat="server" DataKeyNames="UserName" AutoGenerateColumns="False"
                        DataSourceID="ObjectDataSource1">
                        <Columns>
                                <asp:CommandField ShowDeleteButton="True" />
                                <asp:BoundField DataField="ProviderName" HeaderText="ProviderName" ReadOnly="True"
                                        SortExpression="ProviderName" />
                                <asp:CheckBoxField DataField="IsOnline" HeaderText="IsOnline" ReadOnly="True" SortExpression="IsOnline" />
                                <asp:BoundField DataField="LastPasswordChangedDate" HeaderText="LastPasswordChangedDate"
                                        ReadOnly="True" SortExpression="LastPasswordChangedDate" />
                                <asp:BoundField DataField="PasswordQuestion" HeaderText="PasswordQuestion" ReadOnly="True"
                                        SortExpression="PasswordQuestion" />
                                <asp:CheckBoxField DataField="IsLockedOut" HeaderText="IsLockedOut" ReadOnly="True"
                                        SortExpression="IsLockedOut" />
                                <asp:BoundField DataField="Comment" HeaderText="Comment" SortExpression="Comment" />
                                <asp:BoundField DataField="UserName" HeaderText="UserName" ReadOnly="True" SortExpression="UserName" />
                                <asp:BoundField DataField="Email" HeaderText="Email" SortExpression="Email" />
                                <asp:BoundField DataField="CreationDate" HeaderText="CreationDate" ReadOnly="True"
                                        SortExpression="CreationDate" />
                                <asp:CheckBoxField DataField="IsApproved" HeaderText="IsApproved" SortExpression="IsApproved" />
                                <asp:BoundField DataField="LastLockoutDate" HeaderText="LastLockoutDate" ReadOnly="True"
                                        SortExpression="LastLockoutDate" />
                                <asp:BoundField DataField="LastLoginDate" HeaderText="LastLoginDate" SortExpression="LastLoginDate" />
                                <asp:BoundField DataField="LastActivityDate" HeaderText="LastActivityDate" SortExpression="LastActivityDate" />
                        </Columns>
                </asp:GridView>
                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetMembers"
                        TypeName="User" DeleteMethod="DeleteMember">
                        <DeleteParameters>
                                <asp:Parameter Name="username" Type="String" />
                        </DeleteParameters>
                </asp:ObjectDataSource>
        </p>
        <p>
                备注:<br />
                用户和角色之间的操作如下<br />
                Roles.AddUserToRole - 向角色添加用户<br />
                Roles.RemoveUserFromRole - 从角色删除用户<br />
                Roles.GetRolesForUser - 用户所属的角色列表<br />
        </p>
</asp:Content>
 

Security/User.aspx.cs
InBlock.gif using System;
InBlock.gif using System.Data;
InBlock.gif using System.Configuration;
InBlock.gif using System.Collections;
InBlock.gif using System.Web;
InBlock.gif using System.Web.Security;
InBlock.gif using System.Web.UI;
InBlock.gif using System.Web.UI.WebControls;
InBlock.gif using System.Web.UI.WebControls.WebParts;
InBlock.gif using System.Web.UI.HtmlControls;
InBlock.gif
InBlock.gif public partial class Security_User : System.Web.UI.Page
InBlock.gif{
InBlock.gif         protected void Page_Load( object sender, EventArgs e)
InBlock.gif        {
InBlock.gif
InBlock.gif        }
InBlock.gif
InBlock.gif         protected void btnSubmit_Click( object sender, EventArgs e)
InBlock.gif        {
InBlock.gif                MembershipCreateStatus status;
InBlock.gif                Membership.CreateUser(txtUsername.Text.Trim(), txtPassword.Text.Trim(), null, null, null, true, out status);
InBlock.gif
InBlock.gif                 string strInsertMessage = "";
InBlock.gif
InBlock.gif                 switch (status)
InBlock.gif                {
InBlock.gif                         case MembershipCreateStatus.Success:
InBlock.gif
InBlock.gif                                 break;
InBlock.gif                         case MembershipCreateStatus.DuplicateUserName:
InBlock.gif                                strInsertMessage = "用户名重复";
InBlock.gif                                 break;
InBlock.gif                         case MembershipCreateStatus.InvalidUserName:
InBlock.gif                                strInsertMessage = "用户名输入错误";
InBlock.gif                                 break;
InBlock.gif                         case MembershipCreateStatus.InvalidPassword:
InBlock.gif                                strInsertMessage = "密码输入不符合要求";
InBlock.gif                                 break;
InBlock.gif                         default:
InBlock.gif                                strInsertMessage = "出现未知错误";
InBlock.gif                                 break;
InBlock.gif                }
InBlock.gif
InBlock.gif                 if (strInsertMessage != "")
InBlock.gif                {
InBlock.gif                        lblMsg.Text = strInsertMessage;
InBlock.gif                }
InBlock.gif                 else
InBlock.gif                {
InBlock.gif                        lblMsg.Text = "注册成功";
InBlock.gif                        GridView1.DataBind();
InBlock.gif                }
InBlock.gif        }
InBlock.gif}
 
RoleManager测试
App_Code/Role.cs
InBlock.gif using System;
InBlock.gif using System.Data;
InBlock.gif using System.Configuration;
InBlock.gif using System.Web;
InBlock.gif using System.Web.Security;
InBlock.gif using System.Web.UI;
InBlock.gif using System.Web.UI.WebControls;
InBlock.gif using System.Web.UI.WebControls.WebParts;
InBlock.gif using System.Web.UI.HtmlControls;
InBlock.gif
InBlock.gif using System.Collections.Generic;
InBlock.gif using System.ComponentModel;
InBlock.gif
/// <summary>
/// Role 的摘要说明
/// </summary>
InBlock.gif[DataObject( true)]
InBlock.gif public class Role
InBlock.gif{
InBlock.gif         public Role()
InBlock.gif        {
InBlock.gif                 //
InBlock.gif                 // TODO: 在此处添加构造函数逻辑
InBlock.gif                 //
InBlock.gif        }
InBlock.gif
InBlock.gif         /// <summary>
InBlock.gif         ///    得到所有角色
InBlock.gif         /// </summary>
InBlock.gif         /// <param name="userName">用户名称</param>
InBlock.gif         /// <returns></returns>
InBlock.gif        [DataObjectMethod(DataObjectMethodType.Select, true)]
InBlock.gif         static public List<RoleData> GetRoles()
InBlock.gif        {
InBlock.gif                RoleData r = null;
InBlock.gif                List<RoleData> roleList = new List<RoleData>();
InBlock.gif                 string[] ary = Roles.GetAllRoles();
InBlock.gif
InBlock.gif                 foreach ( string s in ary)
InBlock.gif                {
InBlock.gif                        r = new RoleData();
InBlock.gif                        r.RoleName = s;
InBlock.gif
InBlock.gif                        roleList.Add(r);
InBlock.gif                }
InBlock.gif
InBlock.gif                 return roleList;
InBlock.gif        }
InBlock.gif
InBlock.gif         /// <summary>
InBlock.gif         /// 删除角色
InBlock.gif         /// </summary>
InBlock.gif         /// <param name="roleName">角色名称</param>
InBlock.gif        [DataObjectMethod(DataObjectMethodType.Delete, true)]
InBlock.gif         static public void DeleteRole( string roleName)
InBlock.gif        {
InBlock.gif                MembershipUserCollection muc = Membership.GetAllUsers();
InBlock.gif                 string[] allUserNames = new string[1];
InBlock.gif
InBlock.gif                 foreach (MembershipUser mu in muc)
InBlock.gif                {
InBlock.gif                         if (Roles.IsUserInRole(mu.UserName, roleName))
InBlock.gif                        {
InBlock.gif                                allUserNames[0] = mu.UserName;
InBlock.gif                                Roles.RemoveUsersFromRole(allUserNames, roleName);
InBlock.gif                        }
InBlock.gif                }
InBlock.gif                Roles.DeleteRole(roleName);
InBlock.gif        }
InBlock.gif}
InBlock.gif
/// <summary>
/// 角色的实体类
/// </summary>
InBlock.gif public class RoleData
InBlock.gif{
InBlock.gif         protected string _roleName;
InBlock.gif
InBlock.gif         /// <summary>
InBlock.gif         /// 角色名称 关键字
InBlock.gif         /// </summary>
InBlock.gif        [DataObjectField( true)]
InBlock.gif         public string RoleName
InBlock.gif        {
InBlock.gif                get { return this._roleName; }
InBlock.gif                set { this._roleName = value; }
InBlock.gif        }
InBlock.gif}
 
Security/Role.aspx
<%@ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Role.aspx.cs"
        Inherits="Security_Role" Title="RoleManager测试" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
        <p>
                <asp:Label ID="lblMsg" runat="Server" ForeColor="red" />
        </p>
        <p>
                角色名:
                <asp:TextBox ID="txtRolename" runat="server"></asp:TextBox>
        </p>
        <p>
                <asp:Button ID="btnSubmit" runat="server" Text="添加" OnClick="btnSubmit_Click" />
        </p>
        <p>
                <asp:GridView ID="GridView1" runat="server" DataKeyNames="RoleName" DataSourceID="ObjectDataSource1" AutoGenerateColumns="False">
                        <Columns>
                                <asp:CommandField ShowDeleteButton="True" />
                                <asp:BoundField DataField="RoleName" HeaderText="RoleName" ReadOnly="True"
                                        SortExpression="RoleName" />
                        </Columns>
                </asp:GridView>
                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteRole"
                        SelectMethod="GetRoles" TypeName="Role">
                        <DeleteParameters>
                                <asp:Parameter Name="roleName" Type="String" />
                        </DeleteParameters>
                </asp:ObjectDataSource>
        </p>
        <p>
                 备注:<br />
                 用户和角色之间的操作如下<br />
                 Roles.AddUserToRole - 向角色添加用户<br />
                 Roles.RemoveUserFromRole - 从角色删除用户<br />
                 Roles.GetRolesForUser - 用户所属的角色列表<br />
        </p>
</asp:Content>
 
Security/Role.aspx.cs
InBlock.gif using System;
InBlock.gif using System.Data;
InBlock.gif using System.Configuration;
InBlock.gif using System.Collections;
InBlock.gif using System.Web;
InBlock.gif using System.Web.Security;
InBlock.gif using System.Web.UI;
InBlock.gif using System.Web.UI.WebControls;
InBlock.gif using System.Web.UI.WebControls.WebParts;
InBlock.gif using System.Web.UI.HtmlControls;
InBlock.gif
InBlock.gif public partial class Security_Role : System.Web.UI.Page
InBlock.gif{
InBlock.gif         protected void Page_Load( object sender, EventArgs e)
InBlock.gif        {
InBlock.gif
InBlock.gif        }
InBlock.gif
InBlock.gif         protected void btnSubmit_Click( object sender, EventArgs e)
InBlock.gif        {
InBlock.gif                 if (Roles.RoleExists(txtRolename.Text.Trim()))
InBlock.gif                {
InBlock.gif                        lblMsg.Text = "该角色已存在";
InBlock.gif                }
InBlock.gif                 else
InBlock.gif                {
InBlock.gif                        Roles.CreateRole(txtRolename.Text.Trim());
InBlock.gif                        GridView1.DataBind();
InBlock.gif                }
InBlock.gif        }
InBlock.gif}
 
 
注:需要用aspnet_regsql配置数据库


OK
[×××]