浅谈asp.net Forms身份验证详解

在做网站的时候,都会用到用户登录的功能。对于一些敏感的资源,我们只希望被授权的用户才能够访问,这让然需要用户的身份验证。对于初学者,通常将用户登录信息存放在Session中,笔者在刚接触到asp.net的时候就是这么做的。当我将用户信息存在在Session中时,常常会遇到Session丢失导致用户无法正常访问被授权的资源,保持用户登录状态时的安全性问题,无休其实,在asp.net中,我们有更好的解决方案,那就是通过Forms身份验证,从而对用户进行授权,这种方法可以轻松的保持用户的登录状态(如果用户想这样),便捷的用户授权配置,增强的安全性等好处。废话不再多说,下面我们来做一个简单的用

在做例子之前,我们先定义如下用户类,类名为SampleUser,代码如下:

public partial class SampleUser
  {
    string username;
    public string UserName
    {
      get { return username; }
      set { username = value; }
    }

    string userpwd;
    public string UserPWD
    {
      get { return userpwd; }
      set { userpwd = value; }
    }

    public override bool Equals(object obj)
    {
      SampleUser other = obj as SampleUser;
      if (other == null || other.UserName != this.UserName)
        return false;
      return true;
    }
  }

  public partial class SampleUser
  {
    public static List<SampleUser> userList = new List<SampleUser> {
      new SampleUser() { UserName = "01", UserPWD = "123"},
      new SampleUser() { UserName = "02", UserPWD = "123" },
      new SampleUser() { UserName = "03", UserPWD = "123" },
      new SampleUser() { UserName = "04", UserPWD = "123" },
    };

    public static SampleUser GetUser(string userName)
    {
      return userList.Find(u=>u.UserName == userName);
    }
  }

在类SampleUser中,定义了UserName和UserPWD两个字段,分别用来存储用户的登录名和密码信息。在SampleUser类的另一部分中,我们提供了一个用户的静态类表,用来代替存储在数据库中的用户信息,提供一个方法GetUser,用来获取用户信息。

在这个例子中,我们演示用户必须进行登录才能访问网站的资源,如果没有登录,则将用户导航到login.aspx页面中。

第一步,在web.config中添加配置信息,说明网站要使用Forms身份验证,并指定登录页面和默认登录成功后的跳转页面,然后指定拒绝未登录用户的访问,代码如下:

<authentication mode="Forms">
   <forms loginUrl="~/Login.aspx" defaultUrl="~/Default.aspx" />
  </authentication>
  <authorization>
   <deny users="?"/>
  </authorization>

完成这一步后,我们再打开Default.aspx页面,在没有登录的情况下,页面会被导航到Login.aspx页面,我们的第一步的目的已经达到了。

第二步,完成Login.aspx的页面逻辑。在页面中添加两个TextBox控件,用来输入用户名和密码;添加一个CheckBox控件,用来选择是否保持登录状态;添加一个Button控件,响应用户的登录操作。相应的代码如下:

<fieldset>
    <legend>用户登陆</legend>
    <div>
      用户名:<asp:TextBox ID="txtUserID" runat="server" Width="150" /><br /><br />
      密   码:<asp:TextBox ID="txtUserPWD" runat="server" TextMode="Password" Width="150" /><br /><br />
      <asp:CheckBox ID="cbSaveUserName" runat="server" Checked="true" Text="保持登录状态" />
    </div><br />
    <asp:Literal ID="ltMessage" Text="" runat="server" Visible="false" />
    <br />
    <p>
      <asp:Button ID="btnLogin" Text="登陆" runat="server" OnClick="btnLogin_Click" />
    </p>
  </fieldset>

接下来完成后台代码,添加登陆按钮的后台处理方法:对用户名和密码进行验证,如果验证通过,则为用户名创建一个身份验证票据,并将其添加到响应的Cookie中。代码如下:

protected void btnLogin_Click(object sender, EventArgs e)
    {
      string userID = this.txtUserID.Text.Trim();
      string userPWD = this.txtUserPWD.Text.Trim();

      SampleUser userEx = SampleUser.GetUser(userID);
      if (userEx == null)
      {
        ltMessage.Text = "用户不存在!";
        ltMessage.Visible = true;
        return;
      }

      if (userEx.UserPWD != userPWD)
      {
        ltMessage.Text = "用户名或密码错误,请重新输入!";
        ltMessage.Visible = true;
        return;
      }

      //添加票据,并将用户导航到默认页面
      FormsAuthentication.RedirectFromLoginPage(userEx.UserName, this.cbSaveUserName.Checked);
    }

完成这一步后,我们就已经完成了简单Froms验证的功能。运行程序,你会发现,这里存在一个问题!!!

你发现了吗?当我们被导航到login.aspx时,这个页面的样式丢失了!这是因为我们对整个网站的资源进行了访问限制,如果没有登陆,用户不仅无法访问.aspx页面,甚至连css文件、js文件都无法访问。显然,这不是我们想要的,因为这些资源并不是敏感的资源。在通常情况下,我们只希望对部分文件夹中的文件进行验证访问限制,而不是整个网站,例如,我们允许只对User文件夹下的页面进行访问限制,因为这个文件夹中存放的是用户的私人信息,这些信息是敏感的。这该如何实现呢?

为了完成演示分目录验证,我们在项目中添加一个User文件夹,并添加UserInfo.aspx、 UserLogin.aspx两个页面。UserInfo.aspx用来展示用户信息,它的业务逻辑我们不是我们关心的,UserLogin.aspx页面用来让用户登陆,代码跟Login.aspx页面几乎完全相同。

第一步:修改Web.config文件,允许匿名用户访问系统资源。

 <authorization>
   <allow users="?"/>
  </authorization>

第二步:在User文件夹下添加一个Web.config文件,修改代码,拒绝匿名用户访问该文件夹下的资源。

   <authorization>
    <deny users="?"/>
   </authorization>

完成这两步后,我们访问UserInfo.aspx时,如果没有登陆,则会被导航到~/User/UserLogin.aspx页面,当登陆后,又会被导航到~/User/UserInfo.aspx页面。这个时侯,我们的登陆页面样式并没有丢失,这说明我们的配置文件起作用了。

接下来,我们想在UserInfo.aspx页面中显示出已登陆用户的用户名和密码(这里完全是为了演示如何获取登陆用户数据才这样做的,通常用户的密码是不会展示的)。在进行登陆后,用户的票据信息被加密保存在Cookie中,这个票据中,有已登录用户的名称信息,我们通过获取票据中的用户名,即可获取到完整的用户信息。

为了显示用户信息,我们在页面中放置两个Label控件,代码如下:

<h2>
<p>用户名:<asp:Label ID="lblUserName" Text="" runat="server" /></p>
<p>密    码:<asp:Label ID="lblUserPWD" Text="" runat="server" /></p>
</h2>

然后,我们在页面的Load方法中,获取并展示用户信息:

if (this.Context.User != null && this.Context.User.Identity != null && this.Context.User.Identity.IsAuthenticated)
{
  SampleUser user = SampleUser.GetUser(this.Context.User.Identity.Name);
  if (user != null)
  {
    this.lblUserName.Text = user.UserName;
    this.lblUserPWD.Text = user.UserPWD;
  }
}

再次运行我们的代码,当用户登陆后(如果保持登陆状态,即使关掉并重新打开浏览器),我们都可以获取到已登录用户的Name,从而获取用户的对象。

如果要退出登陆,我们只需要删除保存在Cookie中的票证信息即可,这个功能Forms验证已经帮我们完成,代码很简单:

FormsAuthentication.SignOut();  //退出登陆

在本文中,没有涉及到角色的验证,这是因为通过在配置文件中指定角色这种方法并不够灵活,如果角色是可以在程序中维护的,那么我们在这里的指定就形同虚设了。感兴趣的朋友可以自行学习,也并不复杂。在本文的结尾,附上详细的Forms验证在Web.config中的配置说明:

<forms
   name="name"
   loginUrl="URL"
   defaultUrl="URL"
   protection="[All|None|Encryption|Validation]"
   timeout="[MM]"
   path="path"
   requireSSL="[true|false]"
   slidingExpiration="[true|false]">
   enableCrossAppRedirects="[true|false]"
   cookieless="[UseUri|UseCookie|AutoDetect|UseDeviceProfile]"
   domain="domain name"
   ticketCompatibilityMode="[Framework20|Framework40]">
   <credentials>...</credentials>
 </forms>
  • name:指定要用于身份验证的 HTTP Cookie。如果正在一台服务器上运行多个应用程序并且每个应用程序都需要唯一的 Cookie,则必须在每个应用程序的 Web.config 文件中配置 Cookie 名称。默认值为 ".ASPXAUTH"。
  • loginUrl:指定如果找不到任何有效的身份验证 Cookie,将请求重定向到的用于登录的 URL。默认值为 login.aspx。
  • defaultUrl:定义在身份验证之后用于重定向的默认 URL。默认值为 "default.aspx"。
  • protection:指定 Cookie 使用的加密类型(如果有)。默认值为 All。
  • timeout:指定 Cookie 过期前逝去的时间(以整数分钟为单位)。如果 SlidingExpiration 属性为 true,则 timeout 属性是滑动值,会在接收到上一个请求之后的指定时间(以分钟为单位)后过期。 为防止危及性能并避免向开启 Cookie 警告的用户发出多个浏览器警告,当指定的时间逝去大半时将更新 Cookie。这可能导致精确性受损。默认值为 "30"(30 分钟)。
  • path:为应用程序发出的 Cookie 指定路径。默认值是斜杠 ( /),这是因为大多数浏览器是区分大小写的,如果路径大小写不匹配,浏览器不会送回 Cookie。
  • requireSSL:指定是否需要 SSL 连接来传输身份验证 Cookie。默认值为 False。
  • slidingExpiration:指定是否启用可调过期时间。可调过期将 Cookie 的当前身份验证时间重置为在单个会话期间收到每个请求时过期。默认值为 True。
  • enableCrossAppRedirects:表明是否将通过身份验证的用户重定向到其他 Web 应用程序中的 URL。默认值为 False。
  • cookieless:定义是否使用 Cookie 以及 Cookie 的行为。默认值为 UseDeviceProfile.
  • domain:指定在传出 Forms 身份验证 Cookie 中设置的可选域。此设置的优先级高于 httpCookies 元素中使用的域。默认值为空字符串 ("")。
  • ticketCompatibilityMode:指定在 Forms 身份验证中对于票证到期日期使用协调世界时 (UTC) 还是本地时间。默认值为 Framework20。

子元素 credentials:允许选择在配置文件中定义名称和密码凭据。您还可以实现自定义的密码架构,以使用外部源(如数据库)来控制验证。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • ASP.NET Internet安全Forms身份验证方法

    本文分别以ASP.NET1.1与ASP.NET2.0在Forms 身份验证上的实现方法,以及ASP.NET2.0较上一版本有哪些改进或变化进行说明.相信读者都己经看过许多类似这样的文章,不伦是在网上或是某些专业书籍上,最近又有模式&实践小组成员发布WCF安全模型指南,可见构建网站安全总是不过时的话题,作者认为此文也绝对是您应该收藏的参考资料. ASP.NET 安全性的工作原理 网站在安全性方面有一个常见的要求:特定的页面仅允许某些成员或其他经过身份验证的用户浏览.充分利用Forms身份验证是最好

  • asp.net Forms身份验证和基于角色的权限访问

    主要思想:Forms身份验证用来判断是否合法用户,当用户合法后,再通过用户的角色决定能访问的页面. 具体步骤:     1.创建一个网站,结构如下:         网站根目录             Admin目录            ---->    管理员目录                 Manager.aspx        ---->    管理员可以访问的页面             Users目录            ---->    注册用户目录         

  • asp.net forms身份验证,避免重复造轮子

    问题:大家都说使用 forms 验证无法得到当前登录用户除了用户名之外的更多信息,经过我的一番小试验,在 forms 方式下自带的 userdata 可以为我们施展天地的地方.下面记录一下我的操作步骤备忘. step 1: web.config 配置关键地方: web.config配置 复制代码 代码如下: <!-- 通过 <authentication> 节可以配置 ASP.NET 用来 识别进入用户的 安全身份验证模式. --> <authentication mode=

  • Asp.Net二级域名共享Forms身份验证、下载站/图片站的授权访问控制

    一般大家对小文件的解决办法是直接在服务端读取文件,然后输出,这样就避免了文件地址的暴露,这是一种解决办法.而我现在想说的是使用 TransmitFile 方法直接输出文件,但是这个方法对大文件的支撑力度有多少,以及会带来多大的性能开销,我还没有测试过,有兴趣的朋友可以测试下,并发表评论. 好了,进入正题,一般对下载站,大家想到的就是流量的问题,所以自动就想到应该把文件与程序代码分开部署.所以我给文件单独做了一个二级域名,我们就叫 file.xxx.com 吧.主网站域名就是 www.xxx.co

  • 浅谈asp.net Forms身份验证详解

    在做网站的时候,都会用到用户登录的功能.对于一些敏感的资源,我们只希望被授权的用户才能够访问,这让然需要用户的身份验证.对于初学者,通常将用户登录信息存放在Session中,笔者在刚接触到asp.net的时候就是这么做的.当我将用户信息存在在Session中时,常常会遇到Session丢失导致用户无法正常访问被授权的资源,保持用户登录状态时的安全性问题,无休其实,在asp.net中,我们有更好的解决方案,那就是通过Forms身份验证,从而对用户进行授权,这种方法可以轻松的保持用户的登录状态(如果

  • ASP.NET窗体身份验证详解

    asp.net的身份验证类型如下: 在我们实际的工作中,froms身份验证用的还是比较多的,我们接下来详细说一下: 做为web开发的程序员,我想登录窗体是接触的太多了.可是,我发现有的程序员在对身份验证的时候是把验证的用户名保存在一个session里的,然后进入系统的每个页面都去验证session是否为空,如果不为空那么就response.redirect("......aspx").  我认为这种方法相对于asp.net提供的form身份验证来说是不足的,首先,就是增加代码量,因为我

  • ASP.NET Forms身份认证详解

    ASP.NET身份认证基础 在开始今天的内容之前,我想有二个最基础的问题首先要明确: 1. 如何判断当前请求是一个已登录用户发起的? 2. 如何获取当前登录用户的登录名? 在标准的ASP.NET身份认证方式中,上面二个问题的答案是: 1. 如果Request.IsAuthenticated为true,则表示是一个已登录用户. 2. 如果是一个已登录用户,访问HttpContext.User.Identity.Name可获取登录名(都是实例属性). 接下来,本文将会围绕上面二个问题展开,请继续阅读

  • 浅谈AngularJs指令之scope属性详解

    AngularJS使用directive()方法类定义一个指令: .directive("name",function(){ return{ }; }) 上面是定义一个指令的主体框架,该方法接受两个参数: 1.第一个参数:name表示定义的指令的名称(angularjs会用这个name注册这个指令) 2.第二个参数:函数,该番薯必须返回一个对象或者一个函数,但通常我们会返回一个对象.return后接的就是返回的对象. 在返回的对象中有一个scope属性,这个属性用来修饰指令的作用域.

  • 浅谈js-FCC算法Friendly Date Ranges(详解)

    让日期区间更友好! 把常见的日期格式如:YYYY-MM-DD 转换成一种更易读的格式. 易读格式应该是用月份名称代替月份数字,用序数词代替数字来表示天 (1st 代替 1). 记住不要显示那些可以被推测出来的信息: 如果一个日期区间里结束日期与开始日期相差小于一年,则结束日期就不用写年份了.月份开始和结束日期如果在同一个月,则结束日期月份就不用写了. 另外, 如果开始日期年份是当前年份,且结束日期与开始日期小于一年,则开始日期的年份也不用写. 我的代码: function makeFriendl

  • 浅谈PHP之ThinkPHP框架使用详解

    Thinkphp框架其精髓就在于实现了MVC思想,其中M为模板.V为视图.C为控制器,模板一般是公共使用类,在涉及数据库时,一般会跟数据表同名,视图会和控制器类里的方法进行名字的一一对应. 下载及配置 官网(http://www.thinkphp.cn/)下载ThinkPHP5.0,将解压文件放在网站目录下的ATP5子目录下 默认主页:http://localhost:8099/ATP5/public/index.php 如果要隐藏index.php且服务器为Apache则需要将public\.

  • 浅谈C语言=与==的区别详解

    在 C 语言中,最容易产生混淆的操作符要属"="与"==".其中,"="并不等于符号,而是赋值操作符,如 x=3.除此之外,还可以在一个语句中向多个变量赋同一个值,即多重赋值.例如,在下面代码中把 0 同时赋给 x.y 与 z. x = y = z = 0; 相对于只有一个等号的赋值操作符,关系操作符中的等于操作符采用两个等号"=="来表示.正因如此,导致了一个潜在的问题:出于习惯,我们可能经常将需要等于操作符的地方写成赋值操

  • 浅谈JAVA中输入输出流实例详解

    java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象.在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流....本文的目的是为大家介绍JAVA中输入输出流实例详解. 流的层次结构 定义:        java将读取数据对象成为输入流,能向其写入的对象叫输出流.结构图如下: 1.输入输出: 输入/输出(Input/Output)是指对某

随机推荐