使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的: 一,用戶點擊登錄時 對用戶名密碼進行檢查。 當狀態為Success 進而通過用戶名密碼去生成一個身份驗證的令牌 從而對令牌進行加密 生成Token 然後放入Cookie里 二,繼承並重寫 Authorize ...
使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:
- 客戶端使用用戶名跟密碼請求登錄
- 服務端收到請求,去驗證用戶名與密碼
- 驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
- 客戶端收到 Token 以後可以把它存儲起來,比如放在 Cookie 里或者 Local Storage 里
- 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 Token
- 服務端收到請求,然後去驗證客戶端請求裡面帶著的 Token,如果驗證成功,就向客戶端返回請求的數據
一,用戶點擊登錄時 對用戶名密碼進行檢查。 當狀態為Success 進而通過用戶名密碼去生成一個身份驗證的令牌
從而對令牌進行加密 生成Token 然後放入Cookie里
public ActionResult Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return View(model); } LoginManager loginManager = new LoginManager(); var result = loginManager.SignIn(model.Email, model.Password); if (result == LoginState.Success) { var role = loginManager.GetUserRoleByEmailAsync(model.Email); //通過用戶名(郵箱) 密碼生成一個ticket令牌 FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(0, model.Email, DateTime.Now, DateTime.Now.AddMinutes(30), true, string.Format("{0}&{1}", model.Email, model.Password)); //加密 var Token = FormsAuthentication.Encrypt(ticket); System.Web.HttpContext.Current.Session["UserName"]=model.Email; System.Web.HttpContext.Current.Session["Role"] = role; //將Token加入到cookie 並設置為5天過期 var cookie = new HttpCookie("Token", Token) { Expires = DateTime.Now.AddDays(5) }; Response.Cookies.Add(cookie); if (returnUrl != null) { return Redirect(returnUrl); } return Redirect("/Home/Chat"); } return View(); }
二,繼承並重寫 AuthorizeAttribute 中的 OnAuthorization
這裡 我建了個XML文件用來存放action的角色許可權
用來對方法訪問的控制。 這裡會解析token 然後進行匹配
<?xml version="1.0" encoding="utf-8" ?> <Roles> <Controller name="Home"> <Action name="Index"></Action> <Action name="Chat">Admin,VIP5,VIP4</Action> </Controller> <Controller name="Account"> <Action name="Index"></Action> <Action name="GETint">Admin,VIP5,VIP4</Action> </Controller> </Roles>
public class MVCAuthorize : AuthorizeAttribute { public new string Roles { get; set; } //這個是從Action中傳過來的角色 public override void OnAuthorization(AuthorizationContext actionContext) { var token = actionContext.HttpContext.Request.Params["Token"]; if (!string.IsNullOrEmpty(token)) { string controllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName; //得到控制器名稱 string actionName = actionContext.ActionDescriptor.ActionName;//得到Action名稱 string roles = GetActionRoles(actionName, controllerName); // 在Xml文件中根據控制器 Action 找到對應的訪問角色許可權 if (!string.IsNullOrWhiteSpace(roles)) { this.Roles = Roles + "," + roles; var isAuthValidate = ValidateTicket(token, Roles); if (isAuthValidate != AuthorizeState.ValidateSuucss) { base.HandleUnauthorizedRequest(actionContext); } } }
else{
base.HandleUnauthorizedRequest(actionContext);
} } //獲取當前Action的訪問角色 public static string GetActionRoles(string action, string controller) { XElement rootElement = XElement.Load(HttpContext.Current.Server.MapPath("/") + "/XML/RoleAction.xml"); XElement controllerElement = findElementByAttribute(rootElement, "Controller", controller); if (controllerElement != null) { XElement actionElement = findElementByAttribute(controllerElement, "Action", action); if (actionElement != null) { return actionElement.Value; } } return ""; } public static XElement findElementByAttribute(XElement xElement, string tagName, string attribute) { return xElement.Elements(tagName).FirstOrDefault(x => x.Attribute("name").Value.Equals(attribute, StringComparison.OrdinalIgnoreCase)); } //校驗用戶名密碼(對Session匹配,或資料庫數據匹配) private AuthorizeState ValidateTicket(string encryptToken,string role) { if (encryptToken == null) { return AuthorizeState.TokenErro; } //解密Ticket var strTicket = FormsAuthentication.Decrypt(encryptToken).UserData; //從Ticket裡面獲取用戶名和密碼 var index = strTicket.IndexOf("&"); string userName = strTicket.Substring(0, index); string password = strTicket.Substring(index + 1); ArrayList arrayList = new ArrayList(role.Split(',')); var roleName = HttpContext.Current.Session["Role"].ToString(); var name = HttpContext.Current.Session["UserName"].ToString(); //取得session,不通過說明用戶退出,或者session已經過期 if (arrayList.Contains(roleName) && name == userName) //獲取對應控制器 對應方法的訪問角色許可權 如果包含說明符合訪問 否則返回許可權錯誤 { return AuthorizeState.ValidateSuucss; } else { return AuthorizeState.UserValidateErro; } } }
當我們去訪問這個方法時。他會先進行身份驗證。進入MVCAuthorize中。 這裡你可以擴展開來。 比如我臨時需要對這個方法在多開放些角色 ,可以直接在action 帶上
[MVCAuthorize(Roles = "VIP9,ActiveUser")] public ActionResult Chat() { var account = HttpContext.User.Identity.Name; ModelDBContext db = new ModelDBContext(); //ViewBag.UserName =db.User.Where(x=>x.Email == account).FirstOrDefault().FullName; return View(); }
當檢測到用戶未登陸 。 沒有通過認證的同時 去訪問的話。 會返回一個401 你沒有當前頁面許可權訪問
然後就是通過驗證後的樣子
常常是看別人怎麼實現。 還是自己多去實踐 才能成長更快。 加油
工作之餘。手擼代碼。頗有漏洞。望君批正。