In the background, the project consists of a management system (web) and a portal (web), a mobile app (including Android and iOS), three systems sharing a backend, and the backend using Shiro for login authentication and permission control. Okay, so the question is. Can the web and app be Shiro certified? What is the difference between the two? If yes, what is the solution? Looking at everyone's anxious little eyes, the next one to solve the above problems.
Can the Web and app be certified with Shiro Unified login?
OK. If both the Web and the app are logged in with a password, that's not necessarily the case, because for Shiro (this will not introduce Shiro details, only the necessary for this article), no matter who is logged in, with what login (user name password, verification code), as long as through Subject.login Tokens in tokens tell Shiro and then give their own authentication fields within their defined realm, okay, foggy, look at the code.
In the rest of your login to write, such as userrest inside the login method, the user is passed over the parameters subject CurrentUser = Securityutils.getsubject (); Usernamepasswordtoken token = new Usernamepasswordtoken (User.getusername (), User.getpassword ()); Start to enter the Shiro certification process Currentuser.login (token);
The above code is to start using Shiro authentication, call Subject.login (token) to Shiro certification, and then we are related to the custom authentication realm, such as custom Userrealm
Protected AuthenticationInfo Dogetauthenticationinfo (Authenticationtoken authctoken) throws Authenticationexception { //Get tokens based on user name and password//The token is actually passed from Userresource face Currentuser.login (token) //Two tokens are the same. Usernamepasswordtoken token = (usernamepasswordtoken) Authctoken; System.out.println ("Get to token when validating current subject" + reflectiontostringbuilder.tostring (token, Tostringstyle.multi_line_ STYLE)); From the database, the user username corresponding to the username = Userservice.getbyphonenum (Token.getusername ()) is obtained. if (null! = user) { authenticationinfo authcinfo = new Simpleauthenticationinfo (User.getphonenum (), User.getpassword (), GetName ()); return authcinfo; } else{ return null; } }
and a picture.
The diagram depicts a complete login process using Shiro
So the above code shows that currently we have not found the app and Web login D difference, then what is the difference?
The difference between Web and app login certifications
Well, the title is not very accurate, should be logged in and after the login session to keep the difference between the web and the app, first say login:
Login
The app and PC Web require different devices to a large extent determine the difference between the two, the web is generally viewed on the PC, login with the user name and password, if the use of remember password is a cookie authentication, Web login has the following conditions
- Login for the first time, login with username and password
- Close the browser, the session expires, re-login with the password (if you have the Remember password function, you can use a cookie login)
- User Delete cookie or cookie expires, login with username and password
App on mobile device view, the first time you log in with the user name and password, but later if not the user actively quit, should remain logged in, so that there will be a better user experience, but it is not possible to keep the app's session, it is not possible to save the password locally, so the app should be the following process
- Login for the first time, use user name password
- After the user opens the application, the user does not need to enter the password system to automatically log in
- Login with user name and password after user active exit (reload, etc. as active exit)
Seemingly did not see what difference, the only difference is the 2nd: How to log in without a password, the Web is using cookies (automatically maintained by the browser), how to log the app? Because the app does not save the password locally, then also refer to the web, using something like cookies, we call him token bar, the problem solved, the app to save tokens, for security, regular update token, then to see the session to maintain.
Session (hold State)
If the user logged in, how to stay logged on, the web has a cookie and session to solve the problem, the following is a brief look at my understanding of these two things, because the app session is reference to this principle design.
Cookie: is maintained by the browser, each request browser will put the cookie in the header (if any), it can also be seen as JS can access the local storage data location One (the other is storage)
Session: Because HTTP is stateless, but sometimes the server needs to save the requested data for the next request to use, that is, the need to maintain the status of continuous requests, this time the server with the help of cookies, when the browser sends a request to the server, the server generates a unique value , write to the cookie to return to the browser, and generate a Session object, so that the session and cookie value has a one by one correspondence, browsing the next visit will take this cookie value, this time the server will get the value of the cookie, Then find out if there is a session associated with the cookie in your own cache.
Because of the combination of cookies and sessions, Shiro can natively support Web login and session retention, and for the app it can also learn about cookies and session implementations, the only problem being that Web cookies are maintained by the browser, Automatically put the cookie in the header, that our app as long as the server returned by the cookie in the header, every time you visit the server with it.
Password-Free Login
Resolves a login and session retention issue, with a password-free login:
Web: Because the general web page owners need to remember the 7-day password (or a little longer) function, can be implemented using cookies, and Shiro also provides the ability to remember the password, the server-side session does not need to save too long
App: Because the app password login time needs to be longer (when the user does not actively quit, should remain logged in the state), so that the server side to the session to save a long time, to the server memory and performance of a large challenge, the contradiction is: The app takes a long time password-free login , and the server can not save the session for a long time, the workaround:
- The first time the app logs in, uses the username and password, if the login is successful, the cookie is stored locally (such as sharepreference), and the cookie value is saved to the user table in the background.
- The app accesses the server, the app adds the cookie inside the Heade, the server session still exists, can be accessed normally
- The app accesses the server, the app adds the cookie inside the Heade, the server session expires, the access fails, the app automatically takes the cookie stored locally to the server to log in, and the server can log in based on the cookie and user name, The server then has a session, which will generate a new cookie to return to the App,app to update the local cookie, and can be accessed normally
- Users manually quit the app, delete the app stored in the cookie, the next login with a user name and password login
There are problems with this approach:
- Cookies are stored locally in the app, are less secure, and can increase security by encrypting cookies
- Each time the server session expires, the app will have to re-initiate the login request (although the user is not aware of it), but this in itself increases the number of visits, but the request is not very large, but this way makes the cookie frequently updated, but increased security
Here's another way to achieve this:
To achieve their own Sessiondao, the session is saved in the database, so the advantage is that the session will not be piled up in memory, there is no need to consider the session expiration time, for the application of this need long-term preservation session situation, You can save the session indefinitely, without having to resend the login request after each session expires. Here's how it's implemented:
To save the session to the database using Hibernate, create a new simplesessionentity
Package Org.lack.entity;import Java.io.serializable;import Org.apache.shiro.session.mgt.simplesession;import Com.phy.em.user.entity.user;public class Simplesessionentity { private Long ID; Private String Cookie; Private Serializable session; Public Long getId () { return ID; } public void SetId (Long id) { this.id = ID; } Public Serializable Entity () { return session; } public void Setsession (Serializable session) { this.session = session; } Public String GetCookie () { return cookie; } public void Setcookie (String cookie) { This.cookie = cookie; } Public Serializable getsession () { return session; }}
<?xml version= "1.0" encoding= "Utf-8"? ><! DOCTYPE hibernate-mapping Public "-//hibernate/hibernate mapping DTD 3.0//en" "http://hibernate.sourceforge.net/ Hibernate-mapping-3.0.dtd ">
The above is affixed to the simplesessionentity mapping file, especially to note that Hibernate is also supported to save the object in the database, but the entity to implement serializable, when taken out of the strong to the corresponding object can be, So the type of session here is serializable
Create a new session cache class, here inherit from Enterprisecachesessiondao, you can use Ehcache as a level two cache, you must remember to implement save, update, Readsession, delete method, In particular, the Save method simply saves a basic session, and the important attribute are update, which is read from the database in the readsession.
Package Org.lack.daoimport Java.io.serializable;import Java.util.date;import org.apache.log4j.logger;import Org.apache.shiro.session.session;import Org.apache.shiro.session.unknownsessionexception;import Org.apache.shiro.session.mgt.simplesession;import Org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; Import Org.springframework.transaction.annotation.transactional;import Com.phy.em.common.dao.ibasedao;import Com.phy.em.common.shiro.entity.simplesessionentity;import Com.phy.em.user.entity.user;public Class Sessionentitydao extends Enterprisecachesessiondao {private ibasedao<user> Basedao; Private ibasedao<simplesessionentity> Sessiondao; Private Logger log = Logger.getlogger (Sessionentitydao.class); @Override public Serializable Create (session session) {//Save to cache first Serializable cookie = super.create (ses sion); Create a new simplesessionentity, and then save to the database simplesessionentity entity = new simplesessionentity (); Entity.Setsession ((simplesession) session); Entity.setcookie (Cookie.tostring ()); Sessiondao.save (entity); return cookie; } @Override public void Update (session session) throws Unknownsessionexception {Super.update (session); simplesessionentity entity = getentity (Session.getid ()); if (Entity! = null) {entity.setsession ((simplesession) session); Sessiondao.update (entity); }} @Override public Session readsession (Serializable sessionId) throws Unknownsessionexception { Session session = NULL; try{session = Super.readsession (SESSIONID); } catch (Exception e) {}//If the session has been deleted, query the session if (session = = NULL) from the database { simplesessionentity entity = getentity (sessionId); if (entity = null) {session = (session) entity.getsession (); } }
If the app is updated lastaccesstime user user = GetUser (sessionId); if (user! = null) { //If the user is an app user (user is not an empty description), determine if the session expires, and if it expires, modify the last Access Time ((simplesession) session). Setlastaccesstime (New Date ()); }
return session; } @Override public void Delete (session session) {Super.delete (session); Private User GetUser (Serializable sessionId) {String hql = "From user user where User.cookie = '" + Session Id + "'"; Return basedao.finduniquebyhql (HQL); } private simplesessionentity GetEntity (Serializable sessionId) {String hql = "from simplesessionentity enti ty where Entity.cookie = ' "+ sessionId +" ' "; Return sessiondao.finduniquebyhql (HQL); } Private Boolean Isexpire (Session session) {Long timeout = session.gettimeout (); Long lasttime = Session.getlastaccesstime (). GetTime (); Long current = new Date (). GetTime (); if ((Lasttime + timeout) > current) {return false; } return true; } public void Setbasedao (ibasedao<user> basedao) {This.basedao = Basedao; } public void Setsessiondao (ibasedao<simplesessionentity> Sessiondao){This.sessiondao = Sessiondao; } }
I was almost stupid to cry, in succession Enterprisecachesessiondao only realized readsession, delusional oneself new simplesession to return to Shiro use, tried many times after not, After debugging a lot of Shiro source code, found in Simplesession Shiro not only set the basic properties, more importantly, set up the attribute, but my own new simplesession No, so certification is a failure, So please be sure to remember to implement the Save and update methods.
Although took a lot of detours, but with the Shiro source debugging learning, to Shiro understand deeper, no longer just stay in the point that will only use, there is depth.
OK, so far, the text is finished, we begin to solve the problem is finished, write down to break the app login process encountered problems and some of their own experience.
About system securityConsider a number of security considerations when considering app logins
- Encrypt the password when the user logs in with a user name and password
- Session Hold if cookies are used, they can be authenticated after they have been intercepted by others.
- It is certainly inappropriate to save the password locally, if you save the cookie (token), the phone is rooted, it is easy to see, such as Android is just an XML file, so the cookie is saved to encrypt, after encryption improves the crack threshold, Encryption involves the secret key problem, if the secret key is written in the code, Java is anti-compiled after the secret key can be found, of course, Google has already started to support the NDK (ie, Android native development, this native refers to the use of C + + development, compiled into so file, Call in Java), so that the more difficult to crack, using hybrid, not to mention, directly unzip the installation package can be seen.
- If the cookie is stored locally, what is the time (frequency) of the update, so that the cookie is compromised and is only useful for a certain period of time (of course, "This time" is enough for a "conscientious" person to do something)
In considering these issues, I realized:
- Security is only relative (attack and defense is a strong I am stronger, there is attack, the defense will be enhanced, the defense is enhanced, the attack to be more successful to be stronger)
- Security is not technically safer the better, to consider the actual application, the cost of input (often not the technology can not be achieved, but to consider the actual situation, including the cost, the importance of information, etc., this is a kind of engineering thinking)
Shiro implement app and Web unified login