细说ASP.NET Forms身份认证

ASP.NET身份认证基础

在开始今天的博客之前,我想有二个最基础的问题首先要明确:

  1. 如何判断当前请求是一个已登录用户发起的?

  2. 如何获取当前登录用户的登录名?

在标准的ASP.NET身份认证方式中,上面二个问题的答案是:

  1. 如果Request.IsAuthenticated为true,则表示是一个已登录用户。

  2. 如果是一个已登录用户,访问HttpContext.User.Identity.Name可获取登录名(都是实例属性)。

接下来,本文将会围绕上面二个问题展开,请继续阅读。

回到顶部

ASP.NET身份认证过程

在ASP.NET中,整个身份认证的过程其实可分为二个阶段:认证与授权。

  1. 认证阶段:识别当前请求的用户是不是一个可识别(的已登录)用户。

  2. 授权阶段:是否允许当前请求访问指定的资源。

这二个阶段在ASP.NET管线中用AuthenticateRequest和AuthorizeRequest事件来表示。

在认证阶段,ASP.NET会检查当前请求,根据web.config设置的认证方式,尝试构造HttpContext.User对象供我们在后续的处理中使用。 在授权阶段,会检查当前请求所访问的资源是否允许访问,因为有些受保护的页面资源可能要求特定的用户或者用户组才能访问。 所以,即使是一个已登录用户,也有可能会不能访问某些页面。 当发现用户不能访问某个页面资源时,ASP.NET会将请求重定向到登录页面。

受保护的页面与登录页面我们都可以在web.config中指定,具体方法可参考后文。

在ASP.NET中,Forms认证是由FormsAuthenticationModule实现的,URL的授权检查是由UrlAuthorizationModule实现的。

回到顶部

如何实现登录与注销

前面我介绍了可以使用Request.IsAuthenticated来判断当前用户是不是一个已登录用户,那么这一过程又是如何实现的呢?

为了回答这个问题,我准备了一个简单的示例页面,代码如下:

复制代码
<fieldset><legend>用户状态</legend><form action="<%= Request.RawUrl %>" method="post">
    <% if( Request.IsAuthenticated ) { %>
        当前用户已登录,登录名:<%= Context.User.Identity.Name.HtmlEncode() %> <br />            
        <input type="submit" name="Logon" value="退出" />
    <% } else { %>
        <b>当前用户还未登录。</b>
    <% } %>            
</form></fieldset>

页面显示效果如下:

根据前面的代码,我想现在能看到这个页面显示也是正确的,是的,我目前还没有登录*(根本还没有实现这个功能)*。

下面我再加点代码来实现用户登录。页面代码:

复制代码
<fieldset><legend>普通登录</legend><form action="<%= Request.RawUrl %>" method="post">
    登录名:<input type="text" name="loginName" style="width: 200px" value="Fish" />
    <input type="submit" name="NormalLogin" value="登录" />
</form></fieldset>

现在页面的显示效果:

登录与退出登录的实现代码:

复制代码
public void Logon()
{
    FormsAuthentication.SignOut();
}

public void NormalLogin()
{
    // -----------------------------------------------------------------
    // 注意:演示代码为了简单,这里不检查用户名与密码是否正确。
    // -----------------------------------------------------------------

    string loginName = Request.Form["loginName"];
    if( string.IsNullOrEmpty(loginName) )
        return;
    
    FormsAuthentication.SetAuthCookie(loginName, true);

    TryRedirect();
}

现在,我可试一下登录功能。点击登录按钮后,页面的显示效果如下:

从图片的显示可以看出,我前面写的NormalLogin()方法确实可以实现用户登录。

当然了,我也可以在此时点击退出按钮,那么就回到了图片2的显示。

写到这里,我想有必要再来总结一下在ASP.NET中实现登录与注销的方法:

  1. 登录:调用FormsAuthentication.SetAuthCookie()方法,传递一个登录名即可。

  2. 注销:调用FormsAuthentication.SignOut()方法。

回到顶部

保护受限制的页面

在一个ASP.NET网站中,有些页面会允许所有用户访问,包括一些未登录用户,但有些页面则必须是已登录用户才能访问, 还有一些页面可能会要求特定的用户或者用户组的成员才能访问。 这类页面因此也可称为【受限页面】,它们一般代表着比较重要的页面,包含一些重要的操作或功能。

为了保护受限制的页面的访问,ASP.NET提供了一种简单的方式: 可以在web.config中指定受限资源允许哪些用户或者用户组(角色)的访问,也可以设置为禁止访问。

比如,网站有一个页面:MyInfo.aspx,它要求访问这个页面的访问者必须是一个已登录用户,那么可以在web.config中这样配置:

复制代码
<location path="MyInfo.aspx">
    <system.web>
        <authorization>
            <deny users="?"/>
        </authorization>
    </system.web>
</location>

为了方便,我可能会将一些管理相关的多个页面放在Admin目录中,显然这些页面只允许Admin用户组的成员才可以访问。 对于这种情况,我们可以直接针对一个目录设置访问规则:

复制代码
<location path="Admin">
    <system.web>
        <authorization>
            <allow roles="Admin"/>
            <deny users="*"/>
        </authorization>
    </system.web>
</location>

这样就不必一个一个页面单独设置了,还可以在目录中创建一个web.config来指定目录的访问规则,请参考后面的示例。

在前面的示例中,有一点要特别注意的是:

  1. allow和deny之间的顺序一定不能写错了,UrlAuthorizationModule将按这个顺序依次判断。

  2. 如果某个资源只允许某类用户访问,那么最后的一条规则一定是 <deny users="*" />

在allow和deny的配置中,我们可以在一条规则中指定多个用户:

  1. 使用users属性,值为逗号分隔的用户名列表。

  2. 使用roles属性,值为逗号分隔的角色列表。

  3. 问号 (?) 表示匿名用户。

  4. 星号 (*) 表示所有用户。

回到顶部

登录页不能正常显示的问题

有时候,我们可能要开发一个内部使用的网站程序,这类网站程序要求 禁止匿名用户的访问,即:所有使用者必须先登录才能访问。 因此,我们通常会在网站根目录下的web.config中这样设置:

复制代码
<authorization>
    <deny users="?"/>
</authorization>

对于我们的示例,我们也可以这样设置。此时在浏览器打开页面时,呈现效果如下:

从图片中可以看出:页面的样式显示不正确,最下边还多出了一行文字。

这个页面的完整代码是这样的(它引用了一个CSS文件和一个JS文件):

页面最后一行文字平时不显示是因为JScript.js中有以下代码:

复制代码
document.getElementById("hideText").setAttribute("style", "display: none");

这段JS代码能做什么,我想就不用再解释了。

虽然这段JS代码没什么价值,但我主要是想演示在登录页面中引用JS的场景。

根据前面图片,我们可以猜测到:应该是CSS和JS文件没有正确加载造成的。

为了确认就是这样原因,我们可以打开FireBug再来看一下页面加载情况:

相关推荐
史呆芬1 小时前
CodeX多仓库提交Skill搭建
git·后端·openai
埃博拉酱1 小时前
ZEISS Microscopy Installer、ZLMT 及 ZEN 系列软件均因 FlexNet Publisher DLL 崩溃而闪退
后端
fliter1 小时前
Uber 如何完成超大规模 JUnit 迁移:从 JUnit 4 到 JUnit 5 的自动化工程实践
后端
CodeSheep1 小时前
南京IT公司六小龙
前端·后端·程序员
IT_陈寒2 小时前
React useEffect依赖数组把我坑惨了,这次搞明白了
前端·人工智能·后端
环境栈笔记2 小时前
AI 浏览器任务失败怎么排查:Context、Session、Page State 和 Task Log 检查清单
前端·人工智能·后端·自动化
阳光是sunny2 小时前
别再让 AI 瞎找代码了!CodeGraph 这工具能让它秒懂你的项目
前端·后端·ai编程
吾诺2 小时前
2026高温工况双叠自锁垫圈怎么选
后端
xixingzhe22 小时前
Spring 依赖注入
java·后端·spring