MVC5 一套Action的登录控制流程
流程:
用拦截器控制每一个页面请求和ajax请求,根据请求体的cookie里面是否有token判断是否登录,还必须判断该token在redis里面的缓存是否存在
组成部分:
拦截器:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Mvc; using Rongzi.RZR.Huoke.Infrastructure.Util; using Rongzi.RZR.Huoke.Entity; using Rongzi.RZR.Huoke.Entity.Constants; using Rongzi.RZR.Huoke.Infrastructure.Model; using Rongzi.RZR.Huoke.Entity.Models; namespace Rongzi.RZR.Huoke.Infrastructure.Filter { public class ApiAuthFilterAttribute:System.Web.Mvc.ActionFilterAttribute { public bool isDoCheck { get; set; } public ApiAuthFilterAttribute() { isDoCheck = true; } public ApiAuthFilterAttribute(bool isCheck = true) { isDoCheck = isCheck; } public override void OnActionExecuting(ActionExecutingContext actionContext) { if (isDoCheck) { if (actionContext == null || actionContext.HttpContext.Request == null || actionContext.HttpContext.Request.RawUrl == null) { return; } //string token = actionContext.HttpContext.Request.Headers["token"] ?? actionContext.HttpContext.Request.Cookies["token"].Value; string token = actionContext.HttpContext.Request.Cookies["token"]?.Value; if (string.IsNullOrEmpty(token)) { if (actionContext.HttpContext.Request.IsAjaxRequest()) { actionContext.Result = GetAuthJsonResult(); } else { actionContext.HttpContext.Response.Redirect("~/Account/Login"); } return; } RedisOpearteResult redRes = TokenManager<OrganizationUser>.RefreshUserToken(token); if (!redRes.isok) { if (actionContext.HttpContext.Request.IsAjaxRequest()) { actionContext.Result = GetAuthJsonResult(); } else { actionContext.HttpContext.Response.Redirect("~/Account/Login"); } base.OnActionExecuting(actionContext); return; } } base.OnActionExecuting(actionContext); } public static JsonResult GetAuthJsonResult() { var errResponse = new ResponseContext<string>(); errResponse.Head = new ResponseHead(-1, ErrCode.AuthError, "用户还未登录"); return new JsonResult { Data = errResponse, ContentEncoding = System.Text.Encoding.UTF8, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; } public override void OnActionExecuted(ActionExecutedContext actionExecutedContext) { base.OnActionExecuted(actionExecutedContext); } } }
控制登录管理:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security; using Rongzi.RZR.Huoke.Entity.Models; using Rongzi.RZR.Huoke.Infrastructure.Util; using Rongzi.RZR.Huoke.Infrastructure.Model; namespace Rongzi.RZR.Huoke.Infrastructure { public class FormsAuth { ///// <summary> ///// 生成Userdata ///// </summary> ///// <param name="user">用户model</param> ///// <returns></returns> //private static string GenerateUserData(long userId, string userName, string userAccount, string imageUrl) //{ // return string.Join("|", userId, userName, userAccount, imageUrl); //} ///// <summary> ///// 登录系统 ///// </summary> ///// <param name="user">用户model</param> ///// <param name="isRemember"是否记住></param> ///// <param name="days">超时时间</param> //public static void SignIn(long userId, string userName, string userAccount, string imageUrl, bool isRemember, int days) //{ // var userData = GenerateUserData(userId, userName, userAccount, imageUrl); // var enyUserData = DEncrypt.Encrypt(userData); // var ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddDays(days), isRemember, enyUserData); // var enyTicket = FormsAuthentication.Encrypt(ticket); // var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, enyTicket); // HttpContext.Current.Response.Cookies.Add(authCookie); //} /// <summary> /// 登录系统 /// </summary> /// <param name="user"></param> public static void SignIn(OrganizationUser user) { RedisOpearteResult result = TokenManager<OrganizationUser>.getToken(user); var authCookie = new HttpCookie("token", result.token); HttpContext.Current.Response.SetCookie(authCookie); } /// <summary> /// 退出系统 /// </summary> /// <param name="token"></param> public static void SignOff() { var cookie = HttpContext.Current.Request.Cookies["token"]; if (cookie != null) { string token = cookie.Value; TokenManager<OrganizationUser>.LoginOff(token); HttpContext.Current.Response.Cookies["token"].Expires = DateTime.Now.AddDays(-1); } } public static OrganizationUser GetUserInfo() { var cookie = HttpContext.Current.Request.Cookies["token"]; if (cookie != null) { string token = cookie.Value; return TokenManager<OrganizationUser>.getUserByToken(token); } return null; } } }
TokenManager管理:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using Rongzi.Cache.Redis; using System.Configuration; using Rongzi.RZR.Huoke.Infrastructure.Model; namespace Rongzi.RZR.Huoke.Infrastructure.Util { public class TokenManager<TUser> { /// <summary> /// 设置对象过期时间 /// </summary> private static readonly int interval = Convert.ToInt32(ConfigurationManager.AppSettings["Redis_UserExpire"]); private static readonly string prefix = "OrganizationUser:"; /// <summary> /// 存储对象val,获取对应的token /// </summary> /// <param name="val"></param> /// <returns></returns> public static RedisOpearteResult getToken(TUser val) { string tokenID = Guid.NewGuid().ToString(); RedisOpearteResult result = new RedisOpearteResult { isok = RedisCache.Add(prefix + tokenID, val, interval), token = tokenID, result = JsonConvert.SerializeObject(val) }; return result; } /// <summary> /// 根据tokenID更新用户对象 /// </summary> /// <param name="tokenID"></param> /// <param name="val"></param> /// <returns></returns> public static RedisOpearteResult RefreshLoginTokenData(String tokenID, TUser val) { RedisOpearteResult result = new RedisOpearteResult { isok = RedisCache.Add(prefix + tokenID, val, interval), token = tokenID, result = JsonConvert.SerializeObject(val) }; return result; } /// <summary> /// 刷新用户token /// </summary> /// <param name="tokenID"></param> public static RedisOpearteResult RefreshUserToken(string tokenID) { var obj = RedisCache.Get<TUser>(prefix + tokenID); var isExist = obj != null; RedisOpearteResult result = new RedisOpearteResult { isok = isExist, token = tokenID, result = "Token过期" }; if (isExist) { result.result = "成功延迟"; RedisCache.SetExpire(prefix + tokenID, new TimeSpan(0, interval, 0)); } return result; } /// <summary> /// 退出 /// </summary> /// <param name="tokenID"></param> /// <returns></returns> public static RedisOpearteResult LoginOff(string tokenID) { var obj = RedisCache.Get<TUser>(prefix + tokenID); var isExist = obj != null; RedisOpearteResult result = new RedisOpearteResult { isok = isExist, token = tokenID, result = "Token过期" }; if (isExist) { result.result = "退出成功"; RedisCache.Remove(prefix + tokenID); } return result; } /// <summary> /// 通过token 获取用户信息 /// </summary> /// <param name="token">tokenID</param> /// <returns></returns> public static TUser getUserByToken(string tokenID) { if (!string.IsNullOrEmpty(tokenID)) { return RedisCache.Get<TUser>(prefix + tokenID); } return default(TUser); } } }
其他:
public class RedisOpearteResult { public string token { get; set; } public bool isok { get; set; } public int code { get; set; } public object data { get; set; } public string result { get; set; } }
其实整个流程不难,下面说说坑:
Cookie的修改
登录时,不能使用
HttpContext.Current.Response.Cookies.Add(authCookie);
这个是不断的添加cookie,有相同路径的,就添加不同路径的
应该使用:
HttpContext.Current.Response.SetCookie(authCookie);
这个才是唯一性的,有就修改,没有就添加
Cookie的删除:
HttpContext.Current.Response.Cookies.Remove("token");
这个是旧的使用方式,发现怎么也没有用,浏览器中还是有这个cookie,后来查询资料,这个就对服务器中的cookies进行删除,但是并不对浏览器中的cookie进行操作。
应该使用过期时间:
HttpContext.Current.Response.Cookies["token"].Expires = DateTime.Now.AddDays(-1);
还有一点,获取cookie的信息的时候使用Request的,不要使用Response的,发现对象存在,但是里面的值是空字符串
var cookie = HttpContext.Current.Request.Cookies["token"];
上面3个就是我踩的坑,以后注意!