[Switch] permission management 1. ASP. NET Forms identity authentication and forms Identity Authentication
[Switch] permission management learning 1. ASP. NET Forms Identity Authentication
Note: VS2017 and MVC5 are used in this example.
The system is generally inseparable from registration and logon, regardless of its size, scalability, or dash. Next we will analyze the user identity authentication.
Simple login and logout
In the past, when I was studying. net, I didn't know what Forms Identity Authentication was. I used session to log on directly. The effect was quite good. In addition, user information is stored on the server and secure.
Front-end code:
@ If (string. isNullOrWhiteSpace (ViewBag. userName )) {<form action = "/home/login1"> <input type = "text" name = "userName"/> <input type = "submit" value = "Logon"/> </form >}else {<form action = "/home/logout1"> <div> the current user is logged on, login Name: @ ViewBag. userName </div> <input type = "submit" value = "quit"/> </form>}
Background code:
Public ActionResult Index () {ViewBag. UserName = Session ["userName"]?. ToString (); return View ();} public void Login1 (string userName) {if (! String. isNullOrWhiteSpace (userName) // For ease of demonstration, Session ["userName"] = userName; else Session ["userName"] = null; Response. redirect (Request. urlReferrer. localPath); // redirect to the original page} public void Logout1 () {Session ["userName"] = null; Response. redirect (Request. urlReferrer. localPath); // redirect to the original page}
Is it simple and clear. It is useful to extend or customize any features on your own. However, we need to maintain the session. For example, the system is re-released, or iis is automatically restarted. The session will be lost. That is, the user will be inexplicably promoted and need to log on again. Poor experience. (The session service and database are not discussed here ). Since Microsoft has a set of mature permission management systems, why not?
Forms authentication logon and logout
First, enable Forms authentication in web. config:
<system.web> <authentication mode="Forms"></authentication>
Background code:
Public void Login2 (string userName) {if (! String. isNullOrWhiteSpace (userName) // FormsAuthentication is not verified for ease of demonstration. setAuthCookie (userName, true); // log on to Response. redirect (Request. urlReferrer. localPath); // redirect to the original page} public void Logout2 () {FormsAuthentication. signOut (); // logout Response. redirect (Request. urlReferrer. localPath); // redirect to the original page}
Front-end code:
@ If (! Request. isAuthenticated) {<form action = "/home/login2"> <input type = "text" name = "userName"/> <input type = "submit" value = "Logon"/> </form >}else {<form action = "/home/logout2"> <div> the current user is logged on, login Name: @ Context. user. identity. name </div> <input type = "submit" value = "exit"/> </form>}
Such a few codes enable logon and logout. It is different from using session management to log on. Forms authentication directly saves information to the browser. You can also see the method name through SetAuthCookie. However, the Cookie information is encrypted.
It is necessary to describe the relationship between session and cookie. When we use session to maintain the user status, we also use cookies.
However, Forms authentication only stores information in cookies, but does not maintain a session on the server.
If you don't believe it, you can test it. You can log on in either of the two methods, and then clear the session. (How to clear the session? Restart iis, or modify the background code to re-compile and access)
[Note] Why do I need to store cookies for user authentication? Because HTTP is a stateless protocol. For the server, each request is the same. Therefore, users can only be identified by the cookie contained in each request. (Other methods are not considered for the moment)
Custom Identity Authentication
The above logon is simple, but the actual situation is often complicated. Obviously, more user information is required for normal services. Can we extend the identity? The answer is yes.
Background code:
Public void Login3 (string userName) {if (! String. isNullOrWhiteSpace (userName) // For ease of demonstration, {UserInfo user = new UserInfo () {Name = userName, LoginTime = DateTime. now}; // 1. serialize the user information to be saved var data = JsonConvert. serializeObject (user); // 2. Create a FormsAuthenticationTicket that contains the login name and additional user data. FormsAuthenticationTicket ticket = new FormsAuthenticationTicket (2, userName, DateTime. now, DateTime. now. addDays (1), true, data); // 3. encrypt and save string cookieValue = FormsAuthentication. encrypt (ticket); // 4. create a logon Cookie HttpCookie cookie = new HttpCookie (FormsAuthentication. formsCookieName, cookieValue); cookie. httpOnly = true; cookie. secure = FormsAuthentication. requireSSL; cookie. domain = FormsAuthentication. cookieDomain; cookie. path = FormsAuthentication. formsCookiePath; // 5. write the logon Cookie Response. cookies. remove (cookie. name); Response. cookies. add (cookie);} Response. redirect (Request. urlReferrer. localPath); // redirect to the original page}
Then the Application_AuthenticateRequest method in Global. asax is as follows:
Protected void Application_AuthenticateRequest () {GetUserInfo ();} // read user information to HttpContext through coolie decryption. current. userpublic void GetUserInfo () {// 1. read login Cookie HttpCookie cookie = Request. cookies [FormsAuthentication. formsCookieName]; try {UserInfo userData = null; // 2. decrypts the Cookie value and obtains the FormsAuthenticationTicket object FormsAuthenticationTicket ticket = FormsAuthentication. decrypt (cookie. value); if (ticket! = Null & string. isNullOrEmpty (ticket. userData) = false) // 3. restore user data userData = JsonConvert. deserializeObject <UserInfo> (ticket. userData); if (ticket! = Null & userData! = Null) // 4. Construct Our MyFormsPrincipal instance and assign a value to context. User. HttpContext. Current. User = new MyFormsPrincipal <UserInfo> (ticket, userData);} catch {/* exceptions should not be thrown to prevent attackers from testing. */}}
Front-end code:
@ {MyFormsPrincipal <UserInfo> user = Context. user as MyFormsPrincipal <UserInfo>; if (user = null) {<form action = "/home/login3"> <input type = "text" name = "userName"/> <input type = "submit" value = "Logon"/> </form >}else {<form action = "/home/logout2"> <div> the current user is logged on, login Name: @ Context. user. identity. name </div> <div> the current user has logged on. Logon Time: @ user. userData. loginTime </div> <input type = "submit" value = "quit"/> </form> }}
In fact, the entire process andFormsAuthentication. SetAuthCookie (userName, true); // log on
Is equivalent. We only store the data we want to store through expansion.
The process is also relatively simple:
- Construct the data to be stored
- Serialization
- Put the serialization information into the FormsAuthenticationTicket object
- Use FormsAuthentication. Encrypt to Encrypt an object
- Send cookie to Browser
Here, it is a little complicated to decrypt and assign a value to the User.HttpContext.Current.User = new MyFormsPrincipal<UserInfo>(ticket, userData);
.
MyFormsPrincipal interface MyFormsPrincipal
Public class MyFormsPrincipal <TUserData>: IPrincipal where TUserData: class, new () {private IIdentity _ identity; private TUserData _ userData; public MyFormsPrincipal (FormsAuthenticationTicket ticket, TUserData userData) {if (ticket = null) throw new ArgumentNullException ("ticket"); if (userData = null) throw new ArgumentNullException ("userData "); _ identity = new FormsIdentity (ticket); _ userData = userData;} public TUserData UserData {get {return _ userData ;}} public IIdentity Identity {get {return _ identity ;}} public bool IsInRole (string role) // {return false;} is not implemented at the moment ;}}
There is nothing special about it, that is, it is enough to pass in the ticket and custom data during instantiation.
Authorization
With logon, authorization is generally not required. Microsoft is doing a good job. Generally, it is a complete set of items.
[Authorize]public ActionResult LoginOk(){ return View();}
Simply add an Authorize feature to the Action, and this person will automatically check whether or not to log on. If you do not log on, the logon page is automatically displayed. The logon page settings are still in web. config.
<system.web> <authentication mode="Forms" > <forms loginUrl="/home/index"></forms>
This simple authentication is obviously not enough. In many cases, only some people can access some pages. For example, VIP. So we have to expand again.
// Inherit AuthorizeAttributepublic class MyAuthorizeAttribute: AuthorizeAttribute {public override void OnAuthorization (AuthorizationContext filterContext) {if (filterContext. HttpContext. User. Identity. Name! = "Farm Code life") {filterContext. httpContext. response. write ("You are not a vip user and cannot access confidential data"); filterContext. httpContext. response. end (); return;} base. onAuthorization (filterContext );}}
[MyAuthorize]public ActionResult LoginVIP(){ return View();}
Yes, it's that simple. If you have said so much, come to Zhang:
Recommended reading:
- Http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html
Demo:
- Https://github.com/zhaopeiym/blogdemocode/tree/master/permission management /1-formsid Authentication