由于项目要求,还需要加入成员管理以及登陆等内容,简单介绍下自定义成员资格。
具体的项目文件可以参考我的github仓库
判断在线状态的方法
在看过的几种网站代码中,较为常见的有两种,分别是Session保存状态的方式和使用Cookie保存状态的方式,其中Session方式比较简单,但是如果网站较大的话,每个用户分一点服务器的内存,那么这种方式会离服务器宕机不远了,因此较大的网站使用Cookie保存状态是一种比较合适的方法,这种方法被称为票据。
可以做如下理解:当你的票据存在的时候,你的状态显示为在线。一旦票据不存在,那么你的状态就被显示为未登录(或者强制跳转到登录页面)
Iidentity和Iprincipal
Iidentity定义了标识对象的基本功能,里面包括了用户名,验证类型和是否经过验证三种属性,即包含了用户的基本信息。
Iprincipal定义了用户对象的基本功能,主要判断了用户的类别(管理员or普通用户)。
以下是相应的代码:
MyPrinciple.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FWSync.Web
{
public class MyPrinciple:System.Security.Principal.IPrincipal
{
public System.Security.Principal.IIdentity Identity
{
get { return this.identity; }
}
public bool IsInRole(string role)
{
//遍历用户拥有的所有角色
foreach (string r in this.roles)
{
if (r == role)
return true;
}
return false;
}
private System.Security.Principal.IIdentity identity;
private string[] roles;
public MyPrinciple(System.Security.Principal.IIdentity identity, string[] roles)
{
this.identity = identity;
this.roles = roles;
}
}
}
MyIdentity.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
namespace FWSync.Web
{
public class MyIdentity: System.Security.Principal.IIdentity
{
public string AuthenticationType
{
get { return this.authenticationType; }
}
public bool IsAuthenticated
{
get { return this.isAuthenticated; }
}
public string Name
{
get { return this.name; }
}
private string name;
private bool isAuthenticated;
private string authenticationType;
public MyIdentity(string name,string authenticationType)
{
this.name = name;
this.authenticationType = authenticationType;
this.isAuthenticated = !string.IsNullOrEmpty(name);
}
}
}
用户自定义模块
我们在web.config中可以定义用户自定义模块,这个模块可以拿到HttpApplication对象,也就是我们可以通过自定义模块对页面发生的各种请求进行处理,其实简单应用的话和Global.asax差不多。
这里我们要做的是对页面初始化时的请求进行处理。页面初始化时,我们判断下请求的cookie中是否有用户票据。如果有,从票据中提取用户名,包装好后塞进HttpContext中;如果没有,则将空串塞进HttpContext中。(HttpContext我理解为上下文对象,在HttpApplication处理管道中从上到下传递,可以往里面塞一些有用的数据)
这里我并没有写未登录用户跳转到登录页面的功能,实际应用中是需要写的。
web.config中的代码如下:
<httpModules>
<add name="MyModule" type="FWSync.Web.MyModule" />
</httpModules>
MyModule.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FWSync.Web
{
public class MyModule:System.Web.IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}
public void Init(HttpApplication application)
{
application.AuthenticateRequest +=
new EventHandler(Application_AuthenticateRequest);
}
//针对所有请求,就会到这里
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpRequest request = HttpContext.Current.Request;
//找请求的cookie里面是否有用户票据
HttpCookie cookie = request.Cookies["Ticket"];
string name = string.Empty;
if (cookie != null)
{
string ticketstring = cookie.Value;
//解密
System.Web.Security.FormsAuthenticationTicket ticket
= System.Web.Security.FormsAuthentication.Decrypt(ticketstring);
name = ticket.Name;
}
MyIdentity identity = new MyIdentity(name, "Type");
MyPrinciple user = new MyPrinciple(identity, new string[] { });
HttpContext context = HttpContext.Current;
context.Items.Add("User", user);
}
}
}
表现层的使用方式
在表现层中,如果是登录界面,我们需要做的是创建一个票据;如果是其他页面,我们则需要拿到HttpContext中的内容,并判断是否登录成功。
在Login.aspx中,我们只需要对用户进行验证后将用户名加密写入票据中即可,其代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
string name = this.tbxName.Text;
string password = this.tbxPassword.Text;
bool isexist = System.Web.Security.Membership.ValidateUser(name, password);
if (isexist)
{
//生成了票据
System.Web.Security.FormsAuthenticationTicket ticket
= new System.Web.Security.FormsAuthenticationTicket(
2,
name,
DateTime.Now,
DateTime.Now.AddHours(12),
true,
string.Empty
);
//这里需要存储产生的票据
HttpCookie cookie = new HttpCookie("Ticket");
//序列化并加密
string ticketstring =
System.Web.Security.FormsAuthentication.Encrypt(ticket);
cookie.Value = ticketstring;
cookie.Expires = DateTime.Now.AddHours(12);
this.Response.Cookies.Add(cookie);
//这里应该跳转到登录成功的界面之类的地方,先转向主页也一样
this.Response.Redirect("~/Default.aspx");
}
}
}
而在Default.aspx中,我们可以通过HttpContext的内容判断用户票据内容,如果登录,显示用户名;如果未登录,直接显示未登录。
//如果登录,则显示用户名
HttpContext context = this.Context;
MyIdentity identity = context.Items["User"] as MyIdentity;
System.Security.Principal.IPrincipal user = context.Items["User"] as System.Security.Principal.IPrincipal;
if (user.Identity.IsAuthenticated)
{
this.lblLogSta.Text = string.Format("欢迎 {0}", user.Identity.Name);
}
else
{
this.lblLogSta.Text = "未登录";
}
另一种方法
上面写到的功能,微软已经写好了一些内置方法,因此可以略去多行代码。
1、首先可以将MyModule.cs中下列内容进行修改:
//MyIdentity identity = new MyIdentity(name, "Type");
System.Security.Principal.GenericIdentity identity
= new System.Security.Principal.GenericIdentity(name, "Type");
//MyPrinciple user = new MyPrinciple(identity, new string[] { });
System.Security.Principal.GenericPrincipal user
= new System.Security.Principal.GenericPrincipal(identity,new string[] { } );
也就是删去MyIdentity.cs和MyPrinciple.cs后,均采用默认的方式创建。
2、Default.aspx中也可以通过默认的方式拿到用户对象,代码可以精简如下:
HttpContext context = this.Context;
System.Security.Principal.IPrincipal user = this.User;
3、Default.aspx中登录状态的显示可以使用Login控件进行显示,可以删去if (user.Identity.IsAuthenticated)代码段
4、还可以删去MyModule用户自定义模块,同时需要删去Login页面中创建票据的部分和Default页面中登录判断部分,增加web.config中设置部分。
web.config增加部分:
<authentication mode="Forms">
<forms name="Ticket"></forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
这里是指采用表单验证的方式,生成的票据名称为Ticket,所有的页面禁止未登录的用户访问
Login.aspx中判断部分改为如下代码:
if (isexist)
{
System.Web.Security.FormsAuthentication.RedirectFromLoginPage(name, true);
}