ASP.Net:(8)ASP.Net网站安全防御及身份验证

作者:陆金龙    发表时间:2016-08-21 15:31   


1. 高级搜索与网站入侵

g.cn  (www.google.com.hk)

1.1 文件下载搜索 filetype

filetype:ppt 黑客  可搜索到关于黑客内容下载ppt的站点

1.2 搜索敏感目录 index of

index of / password

index of / admin

 

"index of/" password

"index of /" admin

1.3 与(空格)或(|)非(_) 精确搜索""

  小军 小明|小红

  小红_红色

  "红客"

  "黑客"  

1.4 link inurl intext intitle 搜索页面上包含某个url

  intext:mongoDb数据库

  inurl:www.csdn.com

  link:www.hao123.com

1.5 site限定域名

  google搜索中

  site: .jp

  site:.com

  site:.tw

 

  site:xx.com intitle:后台

  site:xx.com intext:管理

  site:xx.com inurl:login

 

  site:xx.com inurl:upfile.asp

  site:xx.com inurl:upload.asp

        Ewebediter.mdb

 如:site:csdn.net intitle:后台 可搜索来源于CSDN站点的关于后台的内容。

1.6 通过robots文件查看

www.baidu.com/robots.txt

robots.txt

User-agent: Baiduspider

Disallow: /baidu

 

User-agent: *

Disallow: /shifen

Disallow: /homepage/

Disallow: /cpro

 

1.7 Url欺骗

http:www.qq.com:www.baidu.com@g.cn 会跳到google的网站

常用的入侵方式为,通过高级搜索和目录拆解,找到登录页面,然后进行使用万能密码或暴力破解登录。

2. 网站编程安全之web.config加密

当web.config文件已经配置好,并准备将网站发布时,先对web.config文件进行加密。

这样即使入侵者获取到了web.config文件,也无法看到敏感的配置信息。

而开发过程中需要经常修改配置项进行功能调试,因次发布网站之后,可以对代码工程的web.config进行解密便于使用。下次发布前再加密即可。

可写一个页面来执行加密和解密操作,为防止被利用,发布网站时从项目中排除即可。

 

添加一个EncodeConfig.aspx页面用来执行加密解码操作。

2.1 web.config加密

使用ConfigurationSection的.SectionInformation.ProtectSection方法加密,加密后程序中读取配置项的方法不变。

1) 导入命名空间

using System.Configuration;

using System.Web.Configuration;

2) 对appsettings配置加密保护

      在页面添加一个命名为btnEncode的按钮,点击事件中进行加密操作。

   protected void btnEncode_Click(object sender, EventArgs e)

        {

            bool res = ProtectAppSettings();

            Response.Write(res ? "加密成功<br/>" : "加密失败¹<br/>");

        }

        

        private bool ProtectAppSettings()

        {

            try

            {

                Configuration config = WebConfigurationManager.OpenWebConfiguration("~/");

                ConfigurationSection appsettings = config.GetSection("appSettings");

                if (!appsettings.SectionInformation.IsProtected)

                {

appsettings.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

                }

                config.Save();

               return true;

            }

            catch (Exception)

            {

                return false;

            }

        }

2.2 web.config解密

使用ConfigurationSection的.SectionInformation.UnprotectSection方法解密,加密后程序中读取配置项的方法不变。

 

在页面添加一个命名为btnDecode的按钮,点击事件中进行解密操作。

 

protected void btnDecode_Click(object sender, EventArgs e)

     {

         bool res = DecodeAppSettings();

         Response.Write(res ? "解密成功" : "解密失败");

     }

       

private bool DecodeAppSettings()

      {

          try

          {

              Configuration config = WebConfigurationManager.OpenWebConfiguration("~/");

              ConfigurationSection appsettings = config.GetSection("appSettings");

              if (appsettings.SectionInformation.IsProtected)

              {

                  appsettings.SectionInformation.UnprotectSection();

              }

              config.Save();

              return true;

          }

          catch (Exception)

          {

              return false;

          }

     }

2.3 加密前后对比

点击加密:

加密前:

加密后:

3. 网站访问的Aspnet身份验证

3.1 用户账号的身份验证

禁止或允许匿名用户、特定用户的访问。只要用户验证通过,就可访问。

     这是最简单的模式,通过web.config配置,所有的匿名访问都跳转到登录页面,登录成功后才能正常访问。

在web.config中设置表单验证模式、登录页面和默认跳转页面,并设置拒绝匿名访问。这样就为所有与web.config同级的页面和同级的文件夹(及下级页面或目录)设置验证要求,访问先跳转到登录页面,登录成功后再跳回需要访问的页面。

如果是直接访问登录页面,登录成功后跳转到配置的默认页面。

3.1.1 整个站点的身份验证配置

     顶级web.config控制对整个站点的资源访问的身份验证

1)设置表单验证模式

     ASP.NET一共有三种身份验证方式,分别为:Forms验证,Windows验证,Passport验证。

  Windows验证:是一种把能够访问到IIS的用户认为是已经通过身份验证的用户。可以通过windows自带的身份验证策略来控制哪些页面用户可以访问,哪些不能访问。这是一种最简单的方式,基本不用写多少代码,全部通过配置就可以实现访问的控制。

  Passport验证:是由微软提供身份验证服务。当然这是收费的。

  Forms验证:就是在用户登录时,向浏览器中添加一个cookie,然后在用户每次访问时都检测这个cookie,从而达到身份验证的目的。

    配置Forms身份验证其实就是把下面代码复制到web.config中,然后进行修改就可以了:

<system.web>
  <authentication mode="Forms">
    <forms loginUrl="Login.aspx"
           protection="All"
           timeout="30"
           name=".ASPXAUTH" 
           path="/"
           slidingExpiration="true"
           defaultUrl="default.aspx"
           cookieless="UseDeviceProfile"/>
  </authentication>
</system.web>

    下面是说明:

· loginUrl指向应用程序的自定义登录页。应该将登录页放在需要安全套接字层 (SSL) 的文件夹中。这有助于确保凭据从浏览器传到 Web 服务器时的完整性。

· protection设置为All,以指定窗体身份验证票的保密性和完整性。这导致使用machineKey元素上指定的算法对身份验证票证进行加密,并且使用同样是machineKey元素上指定的哈希算法进行签名。

· timeout用于指定窗体身份验证会话的有限生存期。默认值为 30 分钟。如果颁发持久的窗体身份验证 Cookie,timeout属性还用于设置持久 Cookie 的生存期。

· namepath设置为应用程序的配置文件中定义的值。

· requireSSL设置为false。该配置意味着身份验证 Cookie 可通过未经 SSL 加密的信道进行传输。如果担心会话窃取,应考虑将requireSSL设置为true

· slidingExpiration设置为true以执行变化的会话生存期。这意味着只要用户在站点上处于活动状态,会话超时就会定期重置。

· defaultUrl设置为应用程序的 Default.aspx 页。

· cookieless设置为UseDeviceProfile,以指定应用程序对所有支持 Cookie 的浏览器都使用 Cookie。如果不支持 Cookie 的浏览器访问该站点,窗体身份验证在 URL 上打包身份验证票。

· enableCrossAppRedirects设置为false,以指明窗体身份验证不支持自动处理在应用程序之间传递的查询字符串上的票证以及作为某个窗体 POST 的一部分传递的票证。

  需要说明一下的是LoginUrl和DefaultUrl属性:

LoginUrl指向登录页面,当ASP.NET判断出该用户请求的资源不允许匿名访问,而该用户未登录时,ASP.NET会自动跳转到LoginUrl所指向的页面,当登录成功后,则跳转回原来请求的页面。

DefaultUrl指向默认页面。当我们直接访问登录页面,并登录成功后,这时ASP.NET会跳转到DefaultUrl指向的页面。其他的选项不写都可以,因为有默认值。

      

  简单的配置示例:

      在<system.web>下找到<authentication>节点,设置mode为Forms,为loginUrl设置登录页面,为defaultUrl默认跳转页面。timeout是身份验证持续有效时间,以下配置为20分钟。

      <authentication mode="Forms">

          <forms loginUrl="~/Login.aspx" timeout="20" defaultUrl="~/bbs.aspx" />

       </authentication>

      

       测试匿名登录:

      测试的需要,在<system.web>下添加<authorization>节点,并添加一个deny项,设置users="?" ,这样就实现了拒绝匿名访问,会跳转到上面配置的登录页。

      配置如下:

  此时访问ContentList页面时,返回的页面如下:

 

2)编写登录成功跳转代码

    匿名登录跳转实现之后,就要考虑登录成功之后的处理了。

在登录页面对登录账号信息进行验证,如果验证通过,则跳回到开始访问的页面或文件夹。实现跳转的关键代码只有两行,如下:

3.1.2 目录级别的身份验证配置

上面说到了,顶级web.config会作用于所有的页面和文件。如果需要为某个文件夹单独设置验证配置,可以在该文件夹下再添加一个web.config文件,这里的只会作用于该文件夹下的页面或子目录。

    父级目录配置能作用于子目录,子文件夹的配置不能作用于父级目录。

在Manage文件夹下的web.config作如下修改,及拒绝匿名访问:

      <authorization>

        < deny users="?"/>

      </authorization>

    将顶级web.config作如下修改,及拒绝用户king访问:

    <authorization>

      <deny users="king" />

    </authorization>

此时两个限制会叠加生效,即匿名用户和king都不能访问Manage文件夹。

而匿名用户则可以访问网站根目录下的所有页面及Manage之外的文件夹。

    

    父级目录配置能作用于子目录的配置项冲突时,子配置项优先。

当二者配置产生冲突时,文件夹下web.config中配置项先被读取而生效。

如Manage文件夹下的web.config作如下配置

      <authorization>

        <allow users="*"/>

      </authorization>

      将顶级web.config作如下修改,及拒绝用户king访问:

    <authorization>

      <deny users="?" />

    </authorization>

此时所有的用户包括匿名用户都可访问Manage文件夹下的页面和目录。如果两者配置互换,则匿名用户将无法访问Manage文件夹了。

3.1.3 单个文件的身份验证配置

我们可以在<system.web>节点之上(必须是上面)再增加一个<location>节点,通过path属性指明location内的配置是单独针对哪个文件。

 

<!--设置页面只允许管理员访问-->

  <location path="EncodeConfig.aspx">

    <system.web>

      <authorization>

        <allow users="admin"/>

        <deny users="*"/>

      </authorization>

    </system.web>

  </location>

 

  <!--公开的内容列表页面允许所有人访问-->

  <location path="ContentList.aspx">

    <system.web>

      <authorization>

        <allow users="*"/>

      </authorization>

    </system.web>

  </location>

 

<system.web>

   

   <!--1.设置表单验证模式-->

    <authentication  mode="Forms">

      <forms loginUrl="~/Login.aspx" timeout="20" name=".ASPXAUTH" slidingExpiration="true" defaultUrl="~/bbs.aspx" cookieless="UseDeviceProfile" />

    </authentication>

   

    <!--2.拒绝匿名用户访问-->

    <authorization>

      <deny users="?"/>

    </authorization>

</system.web>

 

3.2 包含角色的身份验证

如果我们的用户比较多,那么需要在配置文件中把这些用户全部罗列其中。并且以后添加了新用户,还得继续修改配置,太麻烦了!该怎么办呢?通用的做法就是引入角色的概念。给所有的用户分配一个角色,比如:users,admin等。然后我们只需要控制这些角色的访问权限即可。以后添加了新用户只需给这个新用户分配角色,而不用去修改配置,实在是方便。其实,membership也提供了角色的概念,只需要简单的配置一下就可以实现了。

3.2.1 添加数据库支持

  要使用membership首先需要数据库的支持,所以我们第一步就是创建用来存放用户、角色等信息的表结构。别担心,MS早就把创建表的语句写好了,并且还提供了用户界面,让我们点点鼠标就可以创建好所需的结构了。
  具体操作如下:进入C:\WINDOWS\Microsoft.NET\Framework\v2.0.xxxxx(vs2010的目录是v4.0.xxxx)这个目录下,找到aspnet_regsql.exe直接双击运行,就会弹出一个界面,直接下一步。第二个界面让我们选择是添加表结构还是移除,我们当然选择添加,继续下一步。在这个界面中需要填写服务器ip地址以及身份验证信息。在填写完毕后,就可以选择你要将表结构添加到哪个数据库中了。需要注意的是:如果选择默认,则会创建一个新的名叫aspnetdb的数据库,然后将表结构加入其中。一路下一步就完成了数据库结构的添加。

 

附:生成数据库版本与VS工程版本冲突,报错如下

 

The 'System.Web.Security.SqlMembershipProvider' requires a database schema compatible with schema version '1'.  However, the current database schema is not compatible with this version.  You may need to either install a compatible schema with aspnet_regsql.exe (available in the framework installation directory), or upgrade the provider to a newer version.

 

解决步骤:

1).手动删除或用ASP.NET 2.0下的aspnet_regsql.exe工具移除Office数据库MemberShip相关表。

2).用ASP.NET 4.0下的aspnet_regsql.exe工具重新为Office数据库创建MemberShip相关表,问题解决。

3.2.2 web.config配置

好了,表结构添加完毕,接下来就是需要在项目中进行一些简单的配置了。我们在vs中新建一个网站,随后再用记事本打开C:\WINDOWS\Microsoft.NET\Framework\v2.0.xxxxx\CONFIG\machine.config这个文件,找到system.web节点下的membership节点,将整个节点复制到我们新建网站的web.config中的system.web节点中。

 复制过来的代码如下:

    <membership>
      <providers>
        <add name="AspNetSqlMembershipProvider" userlsOnlineTimeWindow="15"
            type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            connectionStringName="LocalSqlServer"
            enablePasswordRetrieval="false" 
            enablePasswordReset="true" 
            requiresQuestionAndAnswer="true" 
            applicationName="/" 
            requiresUniqueEmail="false" 
            passwordFormat="Hashed" 
            maxInvalidPasswordAttempts="5" 
            minRequiredPasswordLength="7" 
            minRequiredNonalphanumericCharacters="1" 
            passwordAttemptWindow="10" 
            passwordStrengthRegularExpression=""/>
      </providers>
    </membership>

    下面是主要的几个属性的含义:

    name:数据提供程序的名称,由于我们是从machine.config复制过来的,所以必须改名,防止重名

    type:数据提供程序类型,如果使用的是MSSQL数据库,则保持不变即可,如果使用的是Oracle等其他数据库,则必须自己创建一个类来继承MembershipProvider抽象基类,重写里边的所有抽象方法,然后把类型写在这里即可。

    connectionStringName:该属性必须指定在<connectionStrings>节点中,一个连接字符串的名字。

    applicationName:应用程序名称,membership允许多个应用程序共同使用一个数据库来管理自己的用户、角色信息,各应用程序只需配置不同的applicationName即可,当然,如果想要多个应用程序使用同一份用户角色信息,只需设置一样的applicationName即可。

    requiresUniqueEmail:顾名思义,用户注册时,是否需要提供未注册过的邮箱。

    passwordFormat:密码存储格式,密码保存在数据库中的格式,最常用的有Clear(不加密)和Hashed(使用SHA1算法加密)
    minRequiredPasswordLength:最小密码长度。

    minRequiredNonalphanumericCharacters:指定有效密码中必须包含的特殊字符的最小数量,就是说不是字母也不是数字的字符的数量,比如 -,.什么的,增加密码强度

    好了,我们将配置修改一下并添加连接字符串:

<connectionStrings>
    <add name="ConnectionString" connectionString="server=.;uid=sa;pwd=sa;database=aspnetdb"/>
</connectionStrings>

<system.web>
    <membership defaultProvider="mySqlMembershipProvider">
      <providers>
        <add name="mySqlMembershipProvider"
            type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
            connectionStringName="ConnectionString"
            enablePasswordRetrieval="false" 
            enablePasswordReset="true" 
            requiresQuestionAndAnswer="true" 
            applicationName="TestMembership" 
            requiresUniqueEmail="true" 
            passwordFormat="Hashed" 
            maxInvalidPasswordAttempts="5" 
            minRequiredPasswordLength="6" 
            minRequiredNonalphanumericCharacters="1" 
            passwordAttemptWindow="10" 
            passwordStrengthRegularExpression=""/>
      </providers>
    </membership>
</system.web>

  上面用黄色高亮字体标注出来的属性,是为了告诉membership采用我们刚才添加的mySqlMembershipProvider这个配置,因为machine.config中有一个AspNetSqlMembershipProvider,我们又在web.config中又添加了一个mySqlMembershipProvider,现在有了两个配置,所以应该使用defaultProvider属性指明本网站使用哪个配置。随后又指定了连接字符串配置的名称,一个Email不允许重复注册,最小密码长度为6,不限制密码中必须含有标点符号等配置。

3.2.3 针对角色进行访问限制的配置

要实现角色功能,非常简单,我们还是去machine.config的<system.web>节点下面找到<roleManager>节点,然后整个节点复制过来到web.config中去,一般会有两个<add>子结点,我们删除一个,留下一个就可以了。全部内容如下:

<roleManager>
  <providers>
    <add name="AspNetSqlRoleProvider"
         connectionStringName="LocalSqlServer" applicationName="/" 
         type="System.Web.Security.SqlRoleProvider" />
  </providers>
</roleManager>

  这个配置比较简单,各项配置和前面配置都一样,不再多说。稍微修改一下:

<roleManager enabled="true" defaultProvider="myAspNetSqlRoleProvider">
  <providers>
    <add name="myAspNetSqlRoleProvider"
         connectionStringName="ConnectionString"
         applicationName="TestMembership" 
         type="System.Web.Security.SqlRoleProvider" />
  </providers>
</roleManager>

3.2.4 ASP.NET控件实现注册

配置成功后该如何应用呢? 现在的用户需要具有一定的角色,使用这样的用户进行登录,才能在Aspnet身份验证中使用角色控制。因此需要重新处理用户的注册和角色分配。  

    ASP.NET给我们提供了一套登录控件,我们可以使用这套控件,轻松的来完成一些通用的功能,例如:注册,登录等。

    1)  ASP.NET控件进行注册

配置好之后第一件事情就是注册用户了,注册用户其实很简单,我们只需新建一个页面,然后在页面中拖出一个CreateUserWizard控件,然后运行页面。好了,没有写一行代码,但是注册功能就已经实现了!就是这么简单!效果见下图:

    

  所有的文本框都是不能为空的,填完所有的空后,点击创建用户。这时,用户就已经被创建了。方便吧!需要注意的是在输入密码时可能会出现“密码最短长度为6,其中必须包含以下非字母数字字符: 1。”这样的提示。这是因为我们在配置的时候<membership>节点下<add>中有两项配置是这样写的:

minRequiredPasswordLength="6"
minRequiredNonalphanumericCharacters="1"

  第一个minRequiredPasswordLength="6"是密码最短长度,我们设定的密码最短为6位

  第二个minRequiredNonalphanumericCharacters="1"这个配置的意思就是说密码中必须包含不是字母也不是数字的字符的个数,是为了加强密码强度,不过这个提示还真是容易让用户费解,我建议还是把这个配置设为0。

    这些提示可能有些给人感觉有点不是非常确切,不过我们可以在该控件的属性窗口中去修改提示的文本,例如:

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server"
            InvalidPasswordErrorMessage="密码最短长度为  {0},其中必须包含以下非字母数字字符: {1}。">
<WizardSteps>
<asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
</asp:CreateUserWizardStep>
<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>

 

默认的外观真的不好看,可以改变控件的默认外观,来看如下代码:

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server"
    InvalidPasswordErrorMessage="密码最短长度为  {0},其中必须包含以下非字母数字字符: {1}。"
    ContinueDestinationPageUrl="~/Default2.aspx">
<WizardSteps>
<asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server">
<ContentTemplate>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>用户名:</td>
<td><asp:TextBox runat="server" ID="UserName"></asp:TextBox></td>
</tr>
<tr>
<td>密码:</td>
<td><asp:TextBox runat="server" ID="Password"></asp:TextBox></td>
</tr>
<tr>
<td>确认密码:</td>
<td><asp:TextBox runat="server" ID="ConfirmPassword" TextMode="Password"></asp:TextBox></td>
</tr>
<tr>
<td>Email:</td>
<td><asp:TextBox runat="server" ID="Email"></asp:TextBox></td>
</tr>
<tr>
<td>安全提示问题:</td>
<td><asp:TextBox runat="server" ID="Question"></asp:TextBox></td>
</tr>
<tr>
<td>安全答案:</td>
<td><asp:TextBox runat="server" ID="Answer"></asp:TextBox></td>
</tr>
<tr>
<td colspan="2" class="style1"><asp:Literal runat="server" ID="ErrorMessage"></asp:Literal></td>
</tr>
</table>
</ContentTemplate>
</asp:CreateUserWizardStep>
<asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server">
<ContentTemplate>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>恭喜!帐户注册成功!</td>
</tr>
<tr><asp:Button runat="server" ID="ContinueButton" CommandName="Continue" Text="完成"/></tr>
</table>
</ContentTemplate>
</asp:CompleteWizardStep>
</WizardSteps>
</asp:CreateUserWizard>

上面的例子使用了自定义模板的方式定制了CreateUserWizard控件的外观,在CreateUserWizardStep下<ContentTemplate>中添加自定义内容,效果见下图:

      

    填写所有内容后,点击创建用户。<CompleteWizardStep>中内容就会显示出来 。效果如下:

  需要注意的是:所有文本框控件的ID属性都是固定的。见下表

  UserName:用户名,必选

  Password:密码,必选

  ConfirmPassword:确认密码,可选

  Email:Email如果web.config中RequireEmail为true,则必选

  Question:密码找回提示问题,如果requiresQuestionAndAnswer为true,则必选

  Answer:密码找回答案,同上

  ErrorMessage:错误提示,可选,这个需要是Label控件或是Literal控件

    

  按钮则需要设置CommandName属性。一共有3种:

  Cancel:取消按钮,可选,可以通过修改CreateUserWizard控件的CancelDestinationPageUrl属性,来设定当用户取消时跳转的页面

  Continue:继续按钮,可选,可以通过修改ContinueDestinationPageUrl属性,来设定当用户注册完成点击继续按钮时跳转到的页面

CreateUser:注册按钮,可选。

 

2) 发送邮件的设置:

在CreateUserWizard控件中加入如下代码:

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server">
<MailDefinition

      BodyFileName="~/mail.txt"
Priority="High"
            From="123@123.com"
            IsBodyHtml="true"
            Subject="新用户注册通知!">
<EmbeddedObjects>
<asp:EmbeddedMailObject Name="customerPic" Path="~/images/DSC00130.jpg"/>
</EmbeddedObjects>
</MailDefinition>
<WizardSteps>
代码省略...
</WizardSteps>
</asp:CreateUserWizard>

     <MailDefinition>这个节点就是确认Email相关的设置,每个属性的具体含义为:  

    BodyFileName:邮件的正文,邮件的正文存放在一个文本文件中,通过该属性指明文本文件的路径即可。

Priority:优先级。

    From:发件人,这个Email就是让注册用户看到的发件人的地址。

    IsBodyHtml:指明发送的正文中是否为HTML,如果在正文中使用了html标签,就必须把该属性设为“true”

    Subject:邮件标题

    <EmbeddedObjects>:在邮件中嵌入的资源列表,如上例,在邮件中可以使用<img src="cid:customerPic" alt="test" />这样的代码来引用

  下面列举mail.txt的内容:

<html>
<head><title></title></head>
<body>
<h1>欢迎您注册本网站</h1>
<p>
您的用户名为:<% UserName %><br/>
您的密码为:<% Password %>
</p>
<p>
<a href="http://www.cnblogs.com/xlb2000">
<img src="cid:customerPic" alt=""/>
</a>
</p>
</body>
</html>

   需要说明的是:在发送邮件之前,控件会将<% UserName %>和<% Password %>分别替换为刚才注册过的用户名和密码。

最后一步:就是需要添加服务器smtp设置,配置如下:

<configuration>
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network host="smtp.126.com" userName="kinglong1984" password="123456" port="25"/>
</smtp>
</mailSettings>
</system.net>
<system.web>
</system.web>
</configuration>

  这个配置告诉CreateUserWizard控件,在发送邮件时的邮件服务器,用户名密码,端口(默认25)等信息

所有配置全部完成,现在可以注册用户了。

这里先注册两个用户:king和admin两个用户,分别分配User和Admin角色。

3.2.5 编写代码注册用户并分配角色

上面已经实现了用户注册,但是没有实现分配角色。

1) 原理说明:

不使用Asp.net自带的登陆控件,而通过编写代码的方式完成注册用户和分配角色功能。

  要使用Membership我们需要引入System.Web.Security这个命名空间。在这个命名空间中有这么几个常用的类:

1. Membership

2. Roles

  Membership类是一个静态类,提供了所有的对于用户方面的操作,比如注册用户,删除用户,取得用户列表,根据email查找用户等等

  方法很多,但是大多数都很简单,我们挑两个比较麻烦点的来详细解释一下:

  Membership.CreateUser方法的功能,看名字就知道是创建用户,这个方法有4个重载:

public static MembershipUser CreateUser(string username, string password);

public static MembershipUser CreateUser(string username, string password, string email);

public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status);

public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);

  这4个重载的返回值都是MembershipUser类,MembershipUser类其实就是一个实体类,不过里边带了一些方法,比如取得密码,修改密码等方法。至于该使用哪个重载,还记得前面的web.config配置么?比如requiresQuestionAndAnswer设置是否需要密码找回问题和答案,如果该设置为true,那么就得使用第三个,或者第四个重载,提供问题和答案了。isApproved这个参数表示创建的用户是否激活。最后一个MembershipCreateStatus是一个枚举,用out关键字修饰,用来获得创建用户的状态,比如:MembershipCreateStatus.Success说明创建用户成功,MembershipCreateStatus.InvalidEmail说明电子邮件的格式错误等等。providerUserKey是一个Guid类型的数据,用来指定该用户的UserId。

  另一个需要介绍的就是public static bool ValidateUser(string username, string password);这个方法,其实看名字和参数大家都应该猜到这个方法的作用了,两个参数分别是用户名和密码,返回值为是否登录成功。剩下的方法都非常的简单了。大家应该一看就明白,不过需要提一下的是:ValidateUser方法经常和FormsAuthentication类配合起来使用,FormsAuthentication类提供了一系列静态方法,用来管理Forms身份验证服务。

  FormsAuthentication类中,常用方法有:

public static string HashPasswordForStoringInConfigFile(string password, string passwordFormat);

public static void SetAuthCookie(string userName, bool createPersistentCookie);
public static void RedirectFromLoginPage(string userName, bool createPersistentCookie);

  第一个HashPasswordForStoringInConfigFile方法,作用很简单,将传入的password按照passwordFormat指定的哈希算法生成哈希密码然后返回,passwordFormat的取值可以是"MD5”或是"SHA1"这两个选择。

  第二个SetAuthCookie方法,向客户端发送身份验证的票据。userName是登陆的用户名,createPersistentCookie用来告诉Asp.net是否创建一个持久的Cookie,让用户下次访问能够免于登陆。

  第三个RedirectFormLoginPage方法,将经过身份验证的用户重定向回最初请求的 URL 或默认 URL。

  通常就是这样的用法:

if (Membership.ValidateUser("zhangsan", "123123"))
{
    FormsAuthentication.RedirectFromLoginPage("zhangsan", false);
}

Roles类同样是一个静态类,里边封装了所有对于角色相关的方法。比如:创建角色、将用户添加到角色,删除角色等常用操作。使用Roles类要注意:web.config配置中roleManager节必须正确配置,并且enabled属性必须等于true才可以使用。

  Roles类中,需要说一下的是AddUserToRole这个方法,这个方法通常和Membership.CreateUser在一起使用,比如:

if (Membership.CreateUser("zhangsan", "123123"))
{
    //创建用户成功,给zhangsan分配User角色
    Roles.AddUserToRole("zhangsan", "User");
}

  这样,在创建zhangsan这个用户之后,顺便给zhangsan分配了User这个角色。在后面,就可以再配置文件中做如下配置:

<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
      <authorization>
        <allow roles="User"/>
        <deny users="?"/>
      </authorization>
    </system.web>
</configuration>

这样,所有新注册的成员才可以访问本目录下的资源

2) 角色添加

    使用如下代码添加角色:

Roles.CreateRole("Admin");
        Roles.CreateRole("Employee");

Roles.CreateRole("User");

3) 注册代码示例

Register.aspx页面代码:

<body>

    <form id="form1" runat="server">

    <div>

 

    <table border="0" cellpadding="0" cellspacing="0">

        <tr>

        <td>用户名:</td>

        <td><asp:TextBox runat="server" ID="UserName"></asp:TextBox></td>

        </tr>

        <tr>

        <td>密码:</td>

        <td><asp:TextBox runat="server" ID="Password" TextMode="Password"></asp:TextBox></td>

        </tr>

        <tr>

        <td>确认密码:</td>

        <td><asp:TextBox runat="server" ID="ConfirmPassword" TextMode="Password"></asp:TextBox></td>

        </tr>

        <tr>

        <td>Email:</td>

        <td><asp:TextBox runat="server" ID="Email"></asp:TextBox></td>

        </tr>

        <tr>

        <td>

        <asp:Button ID="btnRegister" runat="server" Text="注册" 

                onclick="btnRegister_Click" /></td>

        </tr>

    </table>

    </div>

</form>

    <script type="text/javascript">

    <%=msg %>

    </script>

</body>

 

Register.aspx.cs的注册事件代码:

 

protected void btnRegister_Click(object sender, EventArgs e)

        {

            string name = UserName.Text;

            string pass = Password.Text;

            string pass2 = ConfirmPassword.Text;

            if (pass != pass2)

            {

                msg = "alert('两次密码不一致')";

            }

            else

            {

                try

                {

                    if (Membership.CreateUser(name, pass) != null)

                    {

                        Roles.AddUserToRole(name, "User");

                        msg = "alert('注册成功')";

                    }

                }

                catch (Exception ex)

                {

                    msg = "alert('注册失败"  ex.Message "')";

                }

            }

        }

3.2.6 用户登录页面修改和测试

    修改登录后台验证代码:

由于使用了aspnet_regsql.exe生成的数据表存储用户相关信息,这里登录也做相应的修改。页面前台还是一样的,只修改后台的验证代码即可。如下黄色标记的两行:

        protected void btnLogin_Click(object sender, EventArgs e)

        {

            string uName = txtName.Text.Trim();

            //string pass = GetUserPassName(uName);

            //if (pass != null && txtPass.Text == pass)

string pass = txtPass.Text;

if (Membership.ValidateUser(uName, pass))

            {

                FormsAuthentication.SetAuthCookie(uName, false);

                FormsAuthentication.RedirectFromLoginPage(uName, false);

            }

            else

            {

                msg = "alert('登录失败)";

            }

        }

测试角色控制的登录验证:

按照3.2.2介绍的方法进行配置,并且对Manage文件加下的web.config作如下配置,就只有管理员角色的用户才可访问了:

   <system.web>

      <authorization>

        <deny roles="?"/>

        <deny roles="User"/>

        <deny roles="Employee"/>

      </authorization>

     </system.web>

此时浏览Manage文件夹,跳转到登录页。分别使用已创建好的king(User角色)和admin(Admin角色)用户登录来,发现king无法通过验证,而admin可以。

为EncodeConfig.aspx页面做如下设置可以,可以拒绝角色为User的用户访问,而角色为Admin或Employee的用户则可访问:

 

  <location path="EncodeConfig.aspx">

    <system.web>

      <authorization>

    <deny roles="?"/>

        <deny roles="User"/>

      </authorization>

    </system.web>

  </location>