详解ASP.NET MVC Form表单验证(2)

public interface IUserData { bool IsInRole(string role); bool IsInUser(string user); }   接下来定义一个Principal实现IPrincipal接口,如下: public class Principal : IPrincipal { public IIdentity Identity{get;private set;} public IUserData UserData{get;set;} public Principal(FormsAuthenticationTicket ticket, IUserData userData) { EnsureHelper.EnsureNotNull(ticket, "ticket"); EnsureHelper.EnsureNotNull(userData, "userData"); this.Identity = new FormsIdentity(ticket); this.UserData = userData; } public bool IsInRole(string role) { return this.UserData.IsInRole(role); } public bool IsInUser(string user) { return this.UserData.IsInUser(user); } }

  Principal包含IUserData,而不是具体的UserData,这样很容易更换一个UserData而不影响其它代码。Principal的IsInRole和IsInUser间接调用了IUserData的同名方法。

三、写入cookie和读取cookie

  接下来,需要做的就是用户登录成功后,创建UserData,序列化,再利用FormsAuthentication加密,写到cookie中;而请求到来时,需要尝试将cookie解密并反序列化。如下:

public class HttpFormsAuthentication { public static void SetAuthenticationCookie(string userName, IUserData userData, double rememberDays = 0) { EnsureHelper.EnsureNotNullOrEmpty(userName, "userName"); EnsureHelper.EnsureNotNull(userData, "userData"); EnsureHelper.EnsureRange(rememberDays, "rememberDays", 0); //保存在cookie中的信息 string userJson = JsonConvert.SerializeObject(userData); //创建用户票据 double tickekDays = rememberDays == 0 ? 7 : rememberDays; var ticket = new FormsAuthenticationTicket(2, userName, DateTime.Now, DateTime.Now.AddDays(tickekDays), false, userJson); //FormsAuthentication提供web forms身份验证服务 //加密 string encryptValue = FormsAuthentication.Encrypt(ticket); //创建cookie HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptValue); cookie.HttpOnly = true; cookie.Domain = FormsAuthentication.CookieDomain; if (rememberDays > 0) { cookie.Expires = DateTime.Now.AddDays(rememberDays); } HttpContext.Current.Response.Cookies.Remove(cookie.Name); HttpContext.Current.Response.Cookies.Add(cookie); } public static Principal TryParsePrincipal<TUserData>(HttpContext context) where TUserData : IUserData { EnsureHelper.EnsureNotNull(context, "context"); HttpRequest request = context.Request; HttpCookie cookie = request.Cookies[FormsAuthentication.FormsCookieName]; if(cookie == null || string.IsNullOrEmpty(cookie.Value)) { return null; } //解密cookie值 FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value); if(ticket == null || string.IsNullOrEmpty(ticket.UserData)) { return null; } IUserData userData = JsonConvert.DeserializeObject<TUserData>(ticket.UserData); return new Principal(ticket, userData); } }

  在登录时,我们可以类似这样处理:

public ActionResult Login(string userName,string password) { //验证用户名和密码等一些逻辑... UserData userData = new UserData() { UserName = userName, UserID = userID, UserRole = "Admin" }; HttpFormsAuthentication.SetAuthenticationCookie(userName, userData, 7); //验证通过... }

  登录成功后,就会把信息写入cookie,可以通过浏览器观察请求,就会有一个名称为"Form"的Cookie(还需要简单配置一下配置文件),它的值是一个加密后的字符串,后续的请求根据此cookie请求进行验证。具体做法是在HttpApplication的AuthenticateRequest验证事件中调用上面的TryParsePrincipal,如:

protected void Application_AuthenticateRequest(object sender, EventArgs e) { HttpContext.Current.User = HttpFormsAuthentication.TryParsePrincipal<UserData>(HttpContext.Current); }

  这里如果验证不通过,HttpContext.Current.User就是null,表示当前用户未标识。但在这里还不能做任何关于权限的处理,因为上面说到的,有些页面是允许匿名访问的。

三、AuthorizeAttribute

  这是一个Filter,在Action执行前执行,它实现了IActionFilter接口。关于Filter,可以看我之前的这篇文章,这里就不多介绍了。我们定义一个RequestAuthorizeAttribute继承AuthorizeAttribute,并重写它的OnAuthorization方法,如果一个Controller或者Action标记了该特性,那么该方法就会在Action执行前被执行,在这里判断是否已经登录和是否有权限,如果没有则做出相应处理。具体代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wjwdzz.html