• Membership角色与权限管理


    1、Membership简介
    在Asp.Net应用程序中,Membership类用于验证用户凭据并管理用户设置(如密码和电子邮件地址)。Membership类可以独自使用,或者与FormsAuthentication一起使用,以创建一个完整的Web应用程序或网站的用户身份验证系统。Login控件封闭了Membership类,从而提供一种便捷的用户验证机制。

    Membership类提供的功能可用于:
    1) 创建新用户
    2) 将成员资格信息(用户名、密码、电子邮件地址及支持数据)存储在Microsoft Sql Server或其他类似的数据存储区。
    3) 对访问网站的用户进行身份验证。可以以编程方式对用户进行身份验证,也可以使用Login控件创建一个只需很少代码或无需代码的完整的身份验证系统。
    4) 管理密码。包括创建、更改、检索和重置密码等等。可以选择配置Asp.Net成员资格以需求一个密码提示问题及其答案来对忘记密码的用户的密码重置和检索请求进行身份验证。
          默认情况下,Asp.Net成员资格可支持所有Asp.Net应用程序。默认成员资格提供程序为SqlMembershipProvider并在计算机配置中以名称AspNetSqlProvider指定。SqlMemberProvider的默认实例配置为连接到Microsoft Sql Server的一个本地实例。

    2、 Membership在sql server中的设置
    要使用membership,需要对数据库进行一些设置,使用过membership朋友知道,数据库中有一些固有的表、视图和存储过程,我们自己的表中没有这些东西。不过,我们可以通过向导来创建它们,那就是aspnet_regsql.exe,一般来说它位于:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
    它既可以创建数据库中的选项,也可以移除这些设置。
    在运行这个程序之前,我们先在sql server 中建立一个空的数据库。
    建立好后,我们运行aspnet_regsql.exe,指定刚才建的那个空数据库。

    完成之后,空空的数据库就有很多内容了,不过具体的内容暂不必管。继续后面的内容。


    3、配置web.config
    web.config也是要修改的。在system.web节点下添加authentication节点。
    membership既然是用于成员资格管理,当然要求登录验证身份,所以首先加一个forms验证。

    <authentication mode="Forms">
            
    <forms loginUrl="login.aspx" name=".asplogin"/>
          
    </authentication>

    同样在system.web节点下添加membership节点。

          <!--
            defaultProvider:提供程序的名称。默认为AspNetSqlMembershipProvider。如果你有多个Provider的话,指定一个默认值是明智的做法。
            userIsOnlineTimeWindow:指定用户在最近一次活动的日期/时间戳之后被视为联机的分钟数。
            hasAlgorithmType:用于哈希密码的算法的标识符,或为空以使用默认哈希算法。
          
    -->
          
    <membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15" hashAlgorithmType="">
            
    <providers>
              
    <clear/>
              
    <!--
                connectionStringName:membership数据库的连接名称。
                enablePasswordRetrieval:指示当前成员资格提供程序是否配置为允许用户检索其密码。
                enablePasswordReset:指示当前成员资格提供程序是否配置为允许用户重置其密码。
                requiresQuestionAndAnswer:指示默认成员资格提供程序是否要求用户在进行密码重置和检索时回答密码提示问题。
                applicationName:应用程序的名称。
                requiresUniqueemail:指示成员资格提供程序是否配置为要求每个用户名具有唯一的电子邮件地址。
                passwordFormat:指示在成员资格数据存储区中存储密码的格式。值可选Clear,Encrypted和Hashed。
                               Clear:密码以明文形式存储,这可以提高存储和检索密码的性能,但安全性较差,当数据源安全性受到威胁时此类密码很容易被读取。
                               Encrypted:密码在存储时进行了加密码,可以在比较或检索密码时进行解密。此类密码在存储和检索时需要进行额外的处理,但比较安全,在数据源的安全性受到威胁时不容易被获取。
                               Hashed:密码在存储到数据库时使用单向哈希算法和随机生成的salt值进行哈希处理。在验证某一密码时,将用数据库中的salt值对该密码进行哈希计算以进行验证。无法检索啥希密码。
                maxInvalidPasswordAttempts:锁定成员资格用户前允许的无效密码或无效密码提示问题答案尝试次数。
                minRequiredPasswordLength:密码所要求的最小长度。
                minRequiredNonalphanumericCharacters:有效密码在必须包含的最少特殊字符数。
                PasswordAttemptWindow:在锁定成员资格用户之前允许的最大无效密码或无效密码提示问题答案尝试次数的分钟数。这是为了防止不明来源反复尝试来猜测成员资格用户的密码或密码提示问题答案和额外措施。
                passwordStrengthRegularExpression:计算密码的正则表达式。
              
    -->
              
    <add connectionStringName="ConnectionString" enablePasswordRetrieval="false" enablePasswordReset="true" 
                   requiresQuestionAndAnswer
    ="true" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" 
                   maxInvalidPasswordAttempts
    ="5" minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" 
                   passwordAttemptWindow
    ="10" passwordStrengthRegularExpression="" name="AspNetSqlMembershipProvider" 
                   type
    ="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
            
    </providers>
          
    </membership>

    为membership配置web.config后,再配置其角色管理roleManager,也是在system.web下。

          <!--
            cacheRolesInCookie:指示当前用户的角色是否已缓存在某个Cookie中。
                               当CacheRolesInCookie属性在配置文件中设置为true时,每个用户的角色信息就会存储在客户端上的某个Cookie中。
                               当角色管理检查确定某个用户是否属于某个特定角色时,在调用角色提供程序在数据源中检查角色列表之前,将先检查角色Cookie。
                               该Cookie在客户端上会动态更新以缓存最近已验证的角色名称。
          
    -->
          
    <roleManager enabled="true" cacheRolesInCookie="true">
            
    <providers>
              
    <clear/>
              
    <add connectionStringName="ConnectionString" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
            
    </providers>
          
    </roleManager>

    真正步入正题。

    4、创建用户:CreateUserWizard控件
    在vs2005中创建一个asp页面,取名CreateUserWizard.aspx。直接从toolbox中拖入一个CreateUserWizard控件,设置一下FinishDestinationPageUrl属性,该属性指示用户创建完成后,用户点击“继续”后定赂的页面。

    <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" FinishDestinationPageUrl="~/Default.aspx">
                
    <WizardSteps>
                    
    <asp:CreateUserWizardStep runat="server">
                    
    </asp:CreateUserWizardStep>
                    
    <asp:CompleteWizardStep runat="server">
                    
    </asp:CompleteWizardStep>
                
    </WizardSteps>
            
    </asp:CreateUserWizard>

    现在不做任何设置,在vs2005的中design视图中可以看到

    测试一下先!

    提交,出现下面结果:

    所以,正确设置membership后,注册用户就立马可以使用了。这是CreateUserWizard的默认模板,你也可以自己创建你需要的模板,vs2005可以帮你转换出来。你可以修改一下,转换后就是这样。

    所以,正确设置membership后,注册用户就立马可以使用了。这是CreateUserWizard默认模板,你也可以自己创建你需要的模板,vs2005可以帮你转换出来。你可以修改一下,转换后就是这样。

                 <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" ContinueDestinationPageUrl="~/Default.aspx" ActiveStepIndex="1">
                    
    <WizardSteps>
                        
    <asp:CreateUserWizardStep runat="server">
                            
    <ContentTemplate>
                                
    <table border="0">
                                    
    <tr>
                                        
    <td align="center" colspan="2">
                                            注册新帐户
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">用户名:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"
                                                ErrorMessage
    ="必须填写“用户名”。" ToolTip="必须填写“用户名”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">密码:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"
                                                ErrorMessage
    ="必须填写“密码”。" ToolTip="必须填写“密码”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="ConfirmPasswordLabel" runat="server" AssociatedControlID="ConfirmPassword">确认密码:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="ConfirmPassword" runat="server" TextMode="Password"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="ConfirmPasswordRequired" runat="server" ControlToValidate="ConfirmPassword"
                                                ErrorMessage
    ="必须填写“确认密码”。" ToolTip="必须填写“确认密码”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">电子邮件:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="Email" runat="server"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="EmailRequired" runat="server" ControlToValidate="Email"
                                                ErrorMessage
    ="必须填写“电子邮件”。" ToolTip="必须填写“电子邮件”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="QuestionLabel" runat="server" AssociatedControlID="Question">安全提示问题:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="Question" runat="server"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="QuestionRequired" runat="server" ControlToValidate="Question"
                                                ErrorMessage
    ="必须填写“安全提示问题”。" ToolTip="必须填写“安全提示问题”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="AnswerLabel" runat="server" AssociatedControlID="Answer">安全答案:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="Answer" runat="server"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="AnswerRequired" runat="server" ControlToValidate="Answer"
                                                ErrorMessage
    ="必须填写“安全答案”。" ToolTip="必须填写“安全答案”。" ValidationGroup="CreateUserWizard1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="center" colspan="2">
                                            
    <asp:CompareValidator ID="PasswordCompare" runat="server" ControlToCompare="Password"
                                                ControlToValidate
    ="ConfirmPassword" Display="Dynamic" ErrorMessage="“密码”和“确认密码”必须匹配。"
                                                ValidationGroup
    ="CreateUserWizard1"></asp:CompareValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="center" colspan="2" style="color: red">
                                            
    <asp:Literal ID="ErrorMessage" runat="server" EnableViewState="False"></asp:Literal>
                                        
    </td>
                                    
    </tr>
                                
    </table>
                            
    </ContentTemplate>
                            
    <CustomNavigationTemplate>
                                
    <table border="0" cellspacing="5" style=" 100%; height: 100%;">
                                    
    <tr align="right">
                                        
    <td align="right" colspan="0">
                                            
    <asp:Button ID="StepNextButton" runat="server" CommandName="MoveNext" Text="创建用户"
                                                ValidationGroup
    ="CreateUserWizard1" />
                                        
    </td>
                                    
    </tr>
                                
    </table>
                            
    </CustomNavigationTemplate>
                        
    </asp:CreateUserWizardStep>
                        
    <asp:CompleteWizardStep runat="server">
                            
    <ContentTemplate>
                                
    <table border="0">
                                    
    <tr>
                                        
    <td align="center" colspan="2">
                                            完成
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td>
                                            已成功创建您的帐户。
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right" colspan="2">
                                            
    <asp:Button ID="ContinueButton" runat="server" CausesValidation="False" CommandName="Continue"
                                                Text
    ="继续" ValidationGroup="CreateUserWizard1" />
                                        
    </td>
                                    
    </tr>
                                
    </table>
                            
    </ContentTemplate>
                        
    </asp:CompleteWizardStep>
                    
    </WizardSteps>
                    
    <StartNavigationTemplate>
                        
    <asp:Button ID="StartNextButton" runat="server" CommandName="MoveNext" Text="下一步" />
                    
    </StartNavigationTemplate>
                    
    <FinishNavigationTemplate>
                        
    <asp:Button ID="FinishPreviousButton" runat="server" CausesValidation="False" CommandName="MovePrevious"
                            Text
    ="上一步" />
                        
    <asp:Button ID="FinishButton" runat="server" CommandName="MoveComplete" Text="完成" />
                    
    </FinishNavigationTemplate>
                    
    <StepNavigationTemplate>
                        
    <asp:Button ID="StepPreviousButton" runat="server" CausesValidation="False" CommandName="MovePrevious"
                            Text
    ="上一步" />
                        
    <asp:Button ID="StepNextButton" runat="server" CommandName="MoveNext" Text="下一步" />
                    
    </StepNavigationTemplate>
                
    </asp:CreateUserWizard>
     

    5、用户登录Login控件
    CreateuserWizard 可以直接拖出来用,Login控件也是一样。在页面中放一下Login,代码很简单。

    <asp:Login ID="Login1" runat="server" DestinationPageUrl="~/admin/Default.aspx" PasswordRecoveryText="找回密码" PasswordRecoveryUrl="PasswordRecovery.aspx">
    </asp:Login>

    属性解释:
    DestinationPageUrl:设置在登录尝试成功时向用户显示的页面的 URL。
    PasswordRecoveryText:设置密码恢复页链接的文本。
    PasswordRecoveryUrl:设置密码恢复页的 URL。 如果用户忘记密码,可以点击这个链接点找回他的密码。

    同样,你也可以自写模板。

            <asp:Login ID="Login1" runat="server" DestinationPageUrl="~/admin/Default.aspx" PasswordRecoveryText="找回密码" PasswordRecoveryUrl="PasswordRecovery.aspx">
                
    <LayoutTemplate>
                    
    <table border="0" cellpadding="1" cellspacing="0" style="border-collapse: collapse">
                        
    <tr>
                            
    <td>
                                
    <table border="0" cellpadding="0">
                                    
    <tr>
                                        
    <td align="center" colspan="2">
                                            登录
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="UserNameLabel" runat="server" AssociatedControlID="UserName">用户名:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="UserName" runat="server"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="UserNameRequired" runat="server" ControlToValidate="UserName"
                                                ErrorMessage
    ="必须填写“用户名”。" ToolTip="必须填写“用户名”。" ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right">
                                            
    <asp:Label ID="PasswordLabel" runat="server" AssociatedControlID="Password">密码:</asp:Label></td>
                                        
    <td>
                                            
    <asp:TextBox ID="Password" runat="server" TextMode="Password"></asp:TextBox>
                                            
    <asp:RequiredFieldValidator ID="PasswordRequired" runat="server" ControlToValidate="Password"
                                                ErrorMessage
    ="必须填写“密码”。" ToolTip="必须填写“密码”。" ValidationGroup="Login1">*</asp:RequiredFieldValidator>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td colspan="2">
                                            
    <asp:CheckBox ID="RememberMe" runat="server" Text="下次记住我。" />
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="center" colspan="2" style="color: red">
                                            
    <asp:Literal ID="FailureText" runat="server" EnableViewState="False"></asp:Literal>
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td align="right" colspan="2">
                                            
    <asp:Button ID="LoginButton" runat="server" CommandName="Login" Text="登录" ValidationGroup="Login1" />
                                        
    </td>
                                    
    </tr>
                                    
    <tr>
                                        
    <td colspan="2">
                                            
    <asp:HyperLink ID="PasswordRecoveryLink" runat="server" NavigateUrl="PasswordRecovery.aspx">找回密码</asp:HyperLink>
                                        
    </td>
                                    
    </tr>
                                
    </table>
                            
    </td>
                        
    </tr>
                    
    </table>
                
    </LayoutTemplate>
            
    </asp:Login>

    这次先不忙测试。等一下后面的控件!

    6.显示当前用户的名称LoginName控件

    这个控件很简单,就是用来呈现用户名的。

    <asp:LoginName ID="LoginName1" runat="server" FormatString="您好,{0},您目前的身份是:注册用户" />

    如果当前登录的是blueidea,那么显示的就是“您好,blueidea,您目前的身份是:注册用户”。

    7.检测用户的身份验证状态的LoginStatus控件

    可以说是最简单的控件了。

    <asp:LoginStatus ID="LoginStatus1" runat="server" />

    它包含两种状态:1)已登录到网站。2)已从网站注销。
    当用户注销后,会给出一个“登录”的链接,用户可以点击这个链接来登录;当用户登录后,这个控件会自动转变为“注销”状态。

    8.为不同类别用户呈现不同内容的LoginView控件

    全部登录控件都可以直接拿来用,不过,这一个我们来做更多一些东西。

     <asp:LoginView ID="LoginView1" runat="server">
                    <LoggedInTemplate>
                        <asp:LoginName ID="LoginName1" runat="server" FormatString="您好,{0},您已经登录了。" />
                    </LoggedInTemplate>
                    <AnonymousTemplate>
                        <asp:Label ID="Label2" runat="server" Text="您尚未登录,请"></asp:Label><asp:LoginStatus
                            ID="LoginStatus1" runat="server" />
                    </AnonymousTemplate>
                    <RoleGroups>
                        <asp:RoleGroup Roles="admin">
                            <ContentTemplate>
                                <asp:LoginName ID="LoginName1" runat="server" FormatString="您好,{0},您目前的身份是:管理员" />
                                <br />
                                您可以访问:<asp:HyperLink ID="HyperLink1" NavigateUrl="User/Default.aspx" runat="server">User/Default.aspx</asp:HyperLink>
                                <br />
                                您也可以访问:<asp:HyperLink ID="HyperLink2" NavigateUrl="Admin/Default.aspx" runat="server">Admin/Default.aspx</asp:HyperLink>
                                <br />
                                <asp:LoginStatus ID="LoginStatus3" runat="server" />
                            </ContentTemplate>
                        </asp:RoleGroup>
                        <asp:RoleGroup Roles="member">
                            <ContentTemplate>
                                <asp:LoginName ID="LoginName1" runat="server" FormatString="您好,{0},您目前的身份是:注册用户" />
                                <br />
                                您可以访问<asp:HyperLink ID="HyperLink1" NavigateUrl="User/Default.aspx" runat="server">User/Default.aspx</asp:HyperLink>
                                <br />
                                您不能访问<asp:HyperLink ID="HyperLink2" NavigateUrl="Admin/Default.aspx" runat="server">Admin/Default.aspx</asp:HyperLink>
                                <br />
                                <asp:LoginStatus ID="LoginStatus2" runat="server" />
                            </ContentTemplate>
                        </asp:RoleGroup>
                    </RoleGroups>
                </asp:LoginView>

    可以看到,这里包含了三个模板:LoggedInTemplate、AnonymousTemplate和RoleGroup的模板。如果定义了LoggedInTemplate模板,那么该用户会看到该模板内的内容,除非该用户属于另一个角色组,且该角色组在已在RoleGroups的模板中的定义。当匿名用户访问站点时,AnonymousTemplate内的内容会呈现给该用户。在前面我们配置的web.config中启用了角色,我们现在为admin角色定义一个模板,你可以在上面的代码中找到。

    到现在,我们就可以测试一下效果了。

    可以看到,我们还没有登录,AnonymousTemplate的内容呈现在我们的面前。而且其中的LoginStatus显示的状态是“登录”状态。我们登录一下,前面注册了一个用户,登录一下。

    LoggedInTemplate没有起作用,而是member的角色模板起作用,这是因为,其实我们在CreateUserWizard做了设置,新用户注册以后直接纳入member角色组了。在CreateUserWizard的CreatedUser事件中添加一句简单的话:

    protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
        {
            Roles.AddUserToRole(CreateUserWizard1.UserName, "member");
        }

    再来解释一下上面的的“你可以访问……”是什么意思。在此之前我其实已经添加了两个角色:member和admin。角色添加方法很简单:在vs2005中选择 网站->ASP.NET配置->安全->创建或管理角色。跟上面的的配合,我们添加一个角色叫“admin”。

    再选择“创建访问规则”来创建访问规则。给admin文件创建下面规则,如图示:

    拒绝member组和匿名用户,只允许admin组的用户访问admin文件夹。给user文件夹创建如下访问规则。

     拒绝匿名用户,允许member组和admin组的用户。

    当新注册用户登录后,它们可以访问到user文件夹下的文件

    但是,如果访问admin文件夹时则会被定向到登录页。

    9.更改密码的ChangePassword控件

    如果更改密码,就使用它来修改。

     <asp:ChangePassword ID="ChangePassword1" runat="server">
            </asp:ChangePassword>

    不需要设置,就可以修改密码了。

    10.自助找回密码的PasswordRecovery控件

    忘了密码怎么办,可以自已找回啦!不过,在些之前,web.config得另有配置。在system.web中的同级节点创建system.net节点,具体内容如下:

    <system.net>
        <mailSettings>
          <smtp deliveryMethod="Network"   from="*@126.com">
            <network defaultCredentials="false" host="smtp.126.com"   password="*"   port="25"   userName="*@126.com"   />
          </smtp>
        </mailSettings>
      </system.net>

    我们使用了126的邮箱,其中的用户名与密码被省略。创建PasswordRecovery.aspx,放入PasswordRecovery控件。

     <asp:PasswordRecovery ID="PasswordRecovery1" runat="server">
            </asp:PasswordRecovery>

    测试:

    打开注册时填写的邮箱就可以看到了。

     我们就可以使用新的密码来登录站点了。

    11.总结

    membership在接触之前,觉得比较神秘,在接触之后,发现其实也不难懂,而且与login系列控件配合得很完美。如果你想要快速搭建一个用户管理的平台,这是一个不错的选择,是偷懒者的首选。

    如果你嫌MS的控件太难看,也没有关系,因为它又有多种多样的模板,通过自定义模板你就能实现你要看的界面。

    不过,membership是设计得适合大多数的情况,所以也是一种万金油的做法,与你要的功能可能不完全符合,不过,学习一下它的做法,学习它数据库的设计,不也是一个好东西吗?







     

  • 相关阅读:
    CSS伪元素:before/CSS伪元素:before/:after content 显示Font Awesome字体图标:after content 显示Font Awesome字体图标
    window.requestAnimationFrame
    HTML5 canvas clearRect() 方法
    canvas save()和canvas restore()状态的保存和恢复使用方法及实例
    git -分支管理(创建、推送、删除)
    微信小程序设置域名、不校验域名
    微信小程序访问豆瓣api403问题解决方发法
    干货:Vue粒子特效(vue-particles插件)
    chmod命令详细用法
    Python新式类和旧式类的区别
  • 原文地址:https://www.cnblogs.com/luqingfei/p/879891.html
Copyright © 2020-2023  润新知