架构:
基本实现都差不多,有如下几大模块吧:① 都是会有一个 Auth类 或者 Identity类 专门负责处理 登陆、退出、是否登陆、以及Cookie记录等操作。② 在进入每个基本页面(WebForm)或者控制器(MVC-Controller)前会先进入一个处理的方法中,这个方法根据架构不同实现的方式不同。③ 登陆页或登陆控制器,这里的作用傻子都知道,就是在用户登陆或者进入其他带有权限的地方被拦截后跳转到这里处理的。
⑴ WebForm 中实现:
① 这里统一交 Identility 类 吧,这里主要三个方法【登陆、退出、是否登陆】以及一些基本字段(字段供后面使用,如记录日志之类的),登陆方法负责校验账号及密码,这里的密码校验一般是先将密码按照原有的规则采用MD5加密,完后再和库中的用户密码做比较(这是一个md5碰撞的过程),失败则在登陆页面抛错,成功的话要记录会通过FormAuthentication.SetAuthCookie()方法记录Cookie,这里会有人问为什么要通过那个方法来设置Cookie呢?当然你说你任性,可以不用,那你自己来通过解析Cookie来设置IsAuthenticated 从而判断用户是否登陆,这里是为了使用.NET自带的身份认证,使用上述方法后,你可以通过HttpContext.Current.User.Identity.IsAuthenticated来验证用户是否登陆了,因为它返回一个bool值。退出方法就是清掉Cookie,跳转到登陆页面即可,很简单;判断用户是否登陆方法,直接调取刚刚说的HttpContext.Current.User.Identity.IsAuthenticated 或者 调取你自己任性写的 IsAuthenticated 属性也行。
② WebForm实现这一步是通过继承一个基类页面 假设为 PageBase 类,基类 PageBase 又继承 System.Web.UI.Page,在这个基类里要重写 Page 类 的OnInit() 方法,这个方法是在进入页面前先进入这个方法,在这里你可以判断用户是否登陆,未登录则直接 Response.Write("登陆页.aspx");这里注意一点,面试时候有些傻逼面试官会问你子页面的OnInit()方法以及Onload()方法和基类页面的OnInit()和Onload()方法的执行顺序,不要被面试官的淫威所吓倒,这里就是一个递归嵌套执行的过程,先执行子页面的OnInit()方法,这里会调用基类的OnInit(),基类的执行完后,在回到子页面的OnInit()的方法,完后执行完毕,Onload()同理。
③ 这一步最简单了,登陆的调用 Identity 类的登陆方法,退出调用退出方法即可。最多在前端加些请求操作(表单提交或者Ajax异步,看自己喜好)。
⑵ Mvc中实现:
① 第一步这里和Webform实现基本一样,不说了。
② 第二步,既然用的MVC框架,那么就要Filter过滤器来实现了,这里我们可以建一个文件夹命名为Filter,创建一个类,记得类名要以 Attribute 结尾,例如就叫 IdentityAithorizeAttribute,该类需要继承ActionFilterAttribute属性,类内通过重写OnActionExecuting()方法内调用Identity的IsAuthenticated ,判断是否登陆,未登录的话跳转到登陆页。完后在需要限制的控制器或者操作上添加[IdentityAuthorize]特性来实现限制拦截。
③ 同WebFrom的③,Mvc一般会采用Ajax异步的方式提交来提高用户的体验性。
总结:
这只是根据自己现有的技术认知总结出来的,所以可能会存在一定的局限性。写这篇文章之前,觉得可能会有很多内容涉及进来,边写边发现其实好多技术都是相通的,只是实现方式不同罢了,所以越往后写越简略了,当然这和现在的我们对MVC更了解,所以随便写写大家也能看懂,哈哈哈。有一点注意,在插入Cookie的时候一定要设置为只读,不然会有Cookie被串改的风险。脚本是可以操作Cookie的,这一点大家是知道的。
即: System.Web.HttpContext.Current.Response.Cookies[key].HttpOnly = true;
MVC验证登录代码:
登录方法类:
public class Identity { ////// UserID /// private string id = string.Empty; public string ID { get { return id; } set { id = value; } } /// /// 用户名 /// public string UserName { get; set; } public static Identity User { get { try { Identity user = new Identity(); var key = string.Format("{0}.Identity", BuShare.Config.CookiePrefix); var cookies = HttpContext.Current.Request.Cookies; if (cookies != null && cookies.AllKeys.Contains(key)) { var value = cookies[key].Value; if (string.IsNullOrEmpty(value)) { return null; } else { string[] userValue = value.Split('^'); user.ID = userValue[0]; user.UserName = userValue[1]; return user; } } else { return null; } } catch (Exception) { return null; } } } /// /// 注入登录Cookies /// /// public static void Login(En.User user) { var cookies = HttpContext.Current.Response.Cookies; var key = string.Format("{0}.Identity", BuShare.Config.CookiePrefix); cookies[key].Value = CreateCookiesValue(user.ID, user.UserName); cookies[key].HttpOnly = true;//关闭浏览器cookie失效 cookies[key].Domain = BuShare.Config.CookieDomain; var cookiesDelay = HttpContext.Current.Response.Cookies; var keyDelay = string.Format("{0}.Delay", BuShare.Config.CookiePrefix); cookiesDelay[keyDelay].Value = CreateCookiesValue(DateTime.Now.ToString(), "Delay"); cookiesDelay[keyDelay].Expires = DateTime.Now.AddMinutes(30); cookiesDelay[keyDelay].Domain = BuShare.Config.CookieDomain; } /// /// 生成登录Cookies的Value方法 /// /// /// /// private static string CreateCookiesValue(string userID, string username) { try { if (string.IsNullOrWhiteSpace(userID) || string.IsNullOrWhiteSpace(username)) { return ""; } //string clientIP = HttpContext.Current.Request.UserHostAddress; //string userAgent = HttpContext.Current.Request.UserAgent; string value = ""; //TODO:自定义方法生成value;(验证cookie的时候通过该方法对应程序验证) //value通过指定的密钥DES加密 value = Bu.Des.Encrypt(value, Config.SecurityKey); return userID + "^" + HttpUtility.UrlEncode(username) + "^" + value; } catch (Exception) { throw; } } public static bool IsHavingLogin() { try { var key = string.Format("{0}.Identity", Config.CookiePrefix); var cookies = HttpContext.Current.Request.Cookies; #region 延时Cookies var keyDelay = string.Format("{0}.Delay", Config.CookiePrefix); var cookiesDelay = HttpContext.Current.Request.Cookies; if (cookiesDelay != null && cookies != null && cookiesDelay.AllKeys.Contains(keyDelay) && cookies.AllKeys.Contains(key)) { HttpContext.Current.Response.Cookies.Remove(keyDelay); cookiesDelay[keyDelay].Value = CreateCookiesValue(DateTime.Now.ToString(), "Delay"); cookiesDelay[keyDelay].Expires = DateTime.Now.AddMinutes(30); cookiesDelay[keyDelay].Domain = Config.CookieDomain; return true; } else { return false; } #endregion #region 主Cookies if (cookies != null && cookies.AllKeys.Contains(key)) { var value = cookies[key].Value; if (string.IsNullOrEmpty(value)) { return false; } else { string ip = HttpContext.Current.Request.UserHostAddress; return IsValidCookies(value); } } #endregion } catch (Exception) { throw; } } private static bool IsValidCookies(string cookie) { try { if (string.IsNullOrEmpty(cookie)) { return false; } string[] CookiesValues = cookie.Split('^'); if (CookiesValues == null) { return false; } //TODO:自定义方法验证Cookie值(和生成Cookie值得方法对应) //如果cookie值有效 if (TODO:CookiesValues == true) { return true; } } catch (Exception) { throw; } return false; } public static void Logout() { var cookies = HttpContext.Current.Response.Cookies; var key = string.Format("{0}.Identity", Config.CookiePrefix); cookies[key].Value = null; cookies[key].HttpOnly = true;//关闭浏览器cookie失效 cookies[key].Domain = Config.CookieDomain; var cookiesDelay = HttpContext.Current.Response.Cookies; var keyDelay = string.Format("{0}.Delay", Config.CookiePrefix); cookiesDelay[keyDelay].Value = null; cookiesDelay[keyDelay].Expires = DateTime.Now.AddDays(-1); cookiesDelay[keyDelay].Domain = Config.CookieDomain; //返回链接Cookies清理 var cookiesBackUrl = HttpContext.Current.Response.Cookies; var keyBackUrl = "backurl"; cookiesBackUrl[keyBackUrl].Value = null; cookiesBackUrl[keyBackUrl].Expires = DateTime.Now.AddDays(-1); cookiesBackUrl[keyBackUrl].Domain = Config.CookieDomain; } public static bool IsAuthenticated { get { try { var key = string.Format("{0}.Identity", Config.CookiePrefix); var cookies = HttpContext.Current.Request.Cookies; var keyDelay = string.Format("{0}.Delay", Config.CookiePrefix); var cookiesDelay = HttpContext.Current.Request.Cookies; if (cookies != null && cookiesDelay != null && cookies.AllKeys.Contains(key) && cookiesDelay.AllKeys.Contains(keyDelay)) { HttpContext.Current.Response.Cookies.Remove(keyDelay); HttpContext.Current.Response.Cookies[keyDelay].Value = CreateCookiesValue(DateTime.Now.ToString(), "Delay"); HttpContext.Current.Response.Cookies[keyDelay].Expires = DateTime.Now.AddSeconds(30 * 60); HttpContext.Current.Response.Cookies[keyDelay].Domain = Config.CookieDomain; return true; } else { return false; } } catch (Exception) { return false; } } } }
验证登录的Filter:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace Filters { ////// 验证特性(验证是否拥登录) /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] public class IdentityAuthorizeAttribute : ActionFilterAttribute, IActionFilter { /// /// Action执行前 /// /// 上下文 public override void OnActionExecuting(ActionExecutingContext filterContext) { try { if (!Identity.IsAuthenticated)//没有登录的情况 { HttpContext.Current.Response.Clear(); //TODO:未登录下的操作,例如跳转到登录页,记录backUrl等 filterContext.Result = new EmptyResult(); } base.OnActionExecuting(filterContext); } catch (Exception exception) { HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Write(exception.Message); HttpContext.Current.Response.End(); } } } }
在后面代码的方法前加入该Filter验证即可在进入方法前验证登录;
也可用Identity类中关于用户登录信息的操作
PS:转载请注明出处。