在 ASP.NET 中,Session 是控制会话的核心对象,借助 Session,可以保存已登录的用户的信息。可以使用 IHttpModule
的派生类来实现请求的拦截,代码示例如下:
using System;
using System.Diagnostics;
using System.Web;
using System.Web.SessionState;
public class InterceptorModule : IHttpModule, IRequiresSessionState {
public void Dispose() {
//此处放置清除代码。
}
public void Init(HttpApplication context) {
context.AcquireRequestState += new EventHandler(Context_AcquireRequestState);
}
private void Context_AcquireRequestState(object sender, EventArgs e) {
HttpApplication application = sender is HttpApplication ? sender as HttpApplication : null;
if (application == null)
return;
string path = application.Request.Path;
string method = application.Request.HttpMethod;
Debug.WriteLine("[" + method + "] " + path));
// 排除不需要拦截的资源,比如以 /statics 开头的静态资源
if (path.StartsWith("/statics") ||
// 排除登陆页面
path.EndsWith("/login.html") ||
path.EndsWith("/login.aspx") ||
// 排除登录处理程序
path.EndsWith("/Login.ashx") ||
path.EndsWith("/login") ||
// 排除注销处理程序
path.EndsWith("/logout")) {
return;
}
// 首页重定向到 aspx 页面
if ("/".Equals(path)) {
// 当访问 / 的时候,很奇怪的是,session 对象会为 null ,所以这里用重定向来解决了。
// 知道答案的朋友欢迎留言。
application.Response.Redirect("/index.aspx");
return;
}
// 判断用户是否在会话中存在信息,不存在信息的一律重定向到登陆页面
bool logged = application.Context.Session != null &&
application.Context.Session["SDATA"] != null;
if (!logged) {
application.Response.Redirect("/login.aspx?from=interceptor&r=" + new Random().Next());
}
}
}
关于登录处理的逻辑,可以选择在 Web 窗体里做,也可以选择使用一般处理程序或者使用 ASP.NET 处理程序结合Ajax 异步来做。
我们可以将登录的逻辑编写到一个特定的类中,例如在AuthenticatedUser
中:
/// <summary>
/// 已认证的用户
/// </summary>
public class AuthenticatedUser {
public string Name { get; set; }
/// <summary>
/// 认证用户
/// </summary>
/// <param name="username">登录账号</param>
/// <param name="password">登录密码</param>
/// <returns></returns>
public static AuthenticatedUser Authenticate(string username, string password) {
if (string.IsNullOrWhiteSpace(username) ||
string.IsNullOrWhiteSpace(password)) {
throw new ArgumentException("参数异常");
}
// 通过 ADO.NET 实体数据模型来查询数据库
DbEntities entities = new DbEntities();
user user = entities.user.Where(u => u.username.Equals(username) && u.password.Equals(password)).FirstOrDefault();
return user != null ? new AuthenticatedUser {
Name = user.nickname
} : null;
}
}
那么在处理登录的代码中就可直接调用这个静态方法,并将返回的结果直接放到 session 中即可。
login.aspx.cs
protected void Btn_Click(object sender, EventArgs e) {
string u = this.username.Text;
string p = this.password.Text;
AuthenticatedUser user = AuthenticatedUser.Authenticate(u, p);
if (user != null) {
this.Session["SDATA"] = user;
this.Response.Redirect("/");
}
}
login.ashx.cs 或 LoginHandler.cs
public void ProcessRequest(HttpContext context) {
context.Response.ContentType = "text/plain";
string u = context.Request.Form["username"];
string p = context.Request.Form["password"];
AuthenticatedUser user = AuthenticatedUser.Authenticate(u, p);
if (context.Session == null) {
context.Response.Write("Session is null");
return;
}
context.Session["SDATA"] = user;
context.Response.Write(user != null ? "OK" : "NO");
}
如果前端采用 Ajax 将数据提交到一般处理程序或者 ASP.NET 处理程序时,js 的代码如下:
$.post("login.ashx", { username: "root", password: "123",}, function (resp) {
if (resp == "OK") {
location.href = "/";
}
});
另外,需要注意的是:
-
在 HttpModule、一般处理程序、ASP.NET 处理程序中,使用 Session 之前需要先实现
System.Web.SessionState.IRequiresSessionState
接口。 -
使用 HttpModule 或 ASP.NET 处理程序时,需要在
web.config
中配置,如下所示:<system.webServer> <defaultDocument> <files> <add value="index.aspx" /> </files> </defaultDocument> <handlers> <add name="logoutHandler" verb="GET" path="/logout" type="WebApp.App_Code.Handler.LogoutHandler" /> <add name="loginHandler" verb="POST" path="/login" type="WebApp.App_Code.Handler.LoginHandler" /> </handlers> <modules> <add name="im" type="WebApp.App_Code.InterceptorModule,WebApp" /> </modules> </system.webServer>