Correct and elegant resolving user exit problem - JSP and STRUTS solutions

xiaoxiao2021-03-06  111

Summary In a password-protected Web application, properly handle the user exit process does not just call the httpsession invalidate () method. Now there are back and forward buttons on most browsers, allowing users to retreat or move forward to a page. If you press the back button browser in the user after exiting a web application, you will make the user to the user, which will start to worry about whether their personal data is safe. Many web applications are forced to turn off the entire browser when they exit, so that users cannot click the back button. There are also some JavaScript, but this browser is not necessarily played in some client browsers. These solutions are awkward and cannot guarantee 100% effective in either case, and it also requires users to have certain operational experience. This article explains the solution that correctly solves the user's exit problem. Author Kevin Le first describes a password protection web application, and then explains how to generate and discuss solutions in an example program. Although the article is elaborated for JSP pages, the concepts set forth by the author are easily understood to be used for other Web technology. Finally, the author shows how to solve this problem with Jakarta Struts.

Most web applications do not contain confidential information as bank accounts or credit card information, but once we involve sensitive data, we need to provide a class of password protection mechanisms. For example, in a factory, workers access their schedule through the web, enter their training courses, and check their salary, etc. At this point, SSL (Secure Socket Layer) is a bit perception of cow knife, but it is undeniable that we must provide password protection for these applications, otherwise workers (which is the user of web applications) can get other employees in the factory. Private confidential information. Similar to the above situation, there is also a computer in public places such as libraries, hospitals. In these places, many users use several computers, and the personal data of the user protects users is critical. The design is good to write outstanding applications and less requirements for user expertise. Let's take a look at how a perfect web application in the real world is manifested: A user accesses a page via a browser. The web application exhibits a landing page to require the user to enter a valid verification information. The user entered the username and password. At this time we assume that the authentication information provided by the user is correct. After verification process, the web application allows users to browse the area he has access to. When the user wants to exit, click the exit button, the web application requires the user to confirm that he really needs to exit if the user determines exits, the session ends, the web application is repositioned to the landing page. Users can reassure without worrying about his information will leak. Another user sat in front of the same computer, he clicked the back button, the web application should not appear any of the previous users accessible. In fact, the web application should stay on the landing page before providing the correct verification information in the second user. Through the sample program, the article explains how to implement this in a web application.

JSP SAMPLES describes the implementation of the implementation of the implementation of a sample application logoutSampleJSP1 in this article. This example represents many web applications that have not been properly resolved. LogoutSampleJSP1 contains the following JSP pages: login.jsp, home.jsp, secure1.jsp, secure2.jsp, logout.jsp, loginaction.jsp, and logoutAction.jsp. Among them, Home.jsp, Secure1.jsp, Secure2.jsp, and Logout.jsp are not allowed to access unauthenticated users, that is, these pages contain important information, should not be used before or after logging in The appearance is in the browser. Login.jsp contains FORMs for users to enter usernames and passwords. The Logout.jsp page contains the FORM that requires the user to confirm whether to exit. LoginAction.jsp and LogoutAction.jsp use the controller to include login and exit code, respectively. The second example application LogoutSampleJSP2 shows how to solve the problem in the sample logoutSampleJSP1. However, the second application itself has questions. In a particular case, exiting the problem will still appear. The third example application logoutSampleJSP3 has been improved on the second example, which is relatively improved. The last example logoutSampleStruts demonstrates how Struts can solve the login problem. Note: This article is tested on the latest version of Microsoft Internet Explorer (IE), Netscape Navigator, Mozilla, Firefox, and Avant browser.

Login ActionBrian Pontarelli's classic article "J2EE Security: Container VERSUS Custom" discussed different J2EE certified pathways. The article also pointed out that HTTP protocols and Form-based certifications did not provide a mechanism for handling user exiting. Therefore, the solution is to introduce a custom security implementation mechanism. The custom security authentication mechanism generally adopted the authentication information entered from the Form, and then authenticated in a security domain such as LDAP (Lightweight Directory Access Protocol) or relational database. If the authentication information provided by the user is valid, the landing action is injected into an object into the HTTPSession object. HttpSession has an injected object that the user has already logged in. In order to facilitate the readers, the examples attached herein are only written to the HTTPSession to indicate that the user has already logged in. Listing 1 is an excerpt from this piece of code loginAction.jsp page describes Login Actions: Listing 1 //...//initialize RequestDispatcher object; set forward to home page by defaultRequestDispatcher rd = request.getRequestDispatcher ( "home.jsp" ); // prepare connection and statementrs = stmt.executeQuery ("SELECT Password from user where username = '" username "); if (rs.next ()) {// Query Only Returns 1 Record in The Result Set; Only 1 Password Per UserName Which is Also The Primary Key IF ("Password"). Equals (password) {//iffalid password session.settribute ("user", username); // SAVES UserName String in the session object} el match, ie, invalid user password request.setttribute ("error", "invalid password."); rd = request.getRequestDispatcher ("login.jsp");}} // No Record In The Result Set, IE, INVALID Username Else {Request.setttribute ("ERROR", "Invalid User Name); RD = Request.getRequestDispatcher (" Login.jsp ");}} // as a Controller, LoginAction.jsp Finally Either Forwards To "Login.jsp" OR "Home.jsp" RD.Forward (Request, Response); // ... This article is incorporated herein by reference in the relational database, but the views set forth in this question Any type of security domain is applicable.

The Logout Action Exit Action contains a simple delete user name and the INVALIDATE () method for the user's HTTPSession object. Listing 2 is a piece of code from the LoginOutAction.jsp page to exit: Listing 2 // ... session.removeattribute ("user"); session.invalidate (); // ...

Blocking unauthenticated access to protected JSP pages from Form to get the authentication information submitted from the Form and verify that the login movement is written into a username in the HTTPSession object, and the exit action is the opposite work, it from the user The username is deleted in the HTTPSession object and invokes the invalidate () method to destroy httpsession. To make the login and exit action actually play, all protected JSP pages should first verify that the username in the HTTPSession contains the username to confirm if the current user has already logged in. If the username is included in the httpsession, it means that the user has already logged in, the Web application sends the remaining JSP page to the browser, otherwise the JSP page will jump to the login page login.jsp. Page Home.jsp, Secure1.jsp, Secure2.jsp, and Logout.jsp All code segments in Listing 3: Listing 3 //...String UserName = (String) Session.GetaTribute ("User"); if (Null == UserName) {Request.setttribute ("Error", "Session Has ended. please login."); RequestDispatcher Rd = Request.GetRequestDispatcher ("login.jsp"); rd.forward (request, response);} // ... // Allow The Rest of The Dynamic Content in this JSP to be served to the browser // ... In this code segment, the program is reduced from the HTTPSession. If the string is empty, the web application automatically aborts the current page and jumps to the login page, and gives the SESSION HAS Ended. Please log in. If it is not empty, the web application continues, that is, the remaining The page is provided to the user. Running LogoutSampleJSP1 Running LogoutSampleJSP1 will have the following scenarios: • If the user does not log in, the web application will correctly stop the protected page Home.jsp, Secure1.jsp, Secure2.jsp and Logout.jsp execute, that is, if The user touches the address of the Protection JSP page in the browser address bar to try to access, the web application will automatically jump to the login page and prompt session has ended.please log in. • The same, when a user has exited, the web application The execution of the protected page home.jsp, secure1.jsp, secure1.jsp, secure1.jsp, users are exited, if the user exits, if you click the back button on your browser, the web application will not correctly protect the protected pages - After the SESSION destroy (user exits) protected JSP page is displayed in the browser. However, if the user clicks on any link on the page, the web application will jump to the landing page and prompt the session has ended.please log in. Blocking the browser caching the root of the above problem is that most browsers have a back button. When the back button is clicked, the browser is not re-acquired from the web server by default, but is loaded from the browser cache. Java-based web applications do not limit this feature, which also has this problem in WEB applications based on PHP, ASP, and .NET.

After the user clicks the back button, the browser to the server will not be built from the server to the browser. It is not established, just the user, browser, and cache interact. Therefore, even if the code on the list 3 is included to protect the JSP page, these code will not be executed when the rear button is clicked. The good and bad caching is really benevolent to see the benevolence. The cache is indeed a convenience, but you can only feel only on the use of a static HTML page or a graphic or influence page. On the other hand, web applications are usually data-based, data is usually frequently changed. Providing the latest data is more important than reading and displaying expiration data from the cache! Fortunately, HTTP header information "Expires" and "Cache-Control" provide the application server to control the mechanism for cache on the browser and proxy server. HTTP header information Expires tells the proxy server when its cache page will expire. The new defined header information in the HTTP1.1 specification Cache-Control can notify the browser to not cache any page. When you click the back button, the browser re-accesses the server to get the page. The following is the basic method using Cache-Control: • No-cache: Force Cache Get a new page from the server • NO-Store: Cache in any environment does not save Pragma: no-cache equivalent in any page HTTP1.0 specification Cache-Control: No-cache in the HTTP1.1 specification can also be included in the header information. By using the cache control of HTTP header information, the second example application logoutSampleJSP2 solves the problem of logoutSampleJSP1. LogoutSampleJSP2 and LogoutSampleJSP1 Different performances are in the following code segments, this code segment adds to all protected pages: //...response.setheader ("cache-control" "); // forces caches to obtain a new copy of the page from the origin serverresponse.setHeader ( "Cache-Control", "no-store"); // Directs caches not to store the page under any circumstanceresponse.setDateHeader ( "Expires", 0); // causes the proxy cache to see the page as "stale" response.sethead ("pragma", "no-cache"); // http 1.0 backward compatibilityString UserName = (String) session.gettribute ("user"); if (NULL == Username) {Request.setttribute ("Error", "Session Has ended. Please login."); RequestDispatcher rd = Request.GetRequestDispatcher ("login.jsp"); rd.forward (request, response);} // ... By setting the header information and check the username in the httpsession, make sure the browser does not cache the page, and if the user is not logged in, the protected JSP page will not be sent to the browser, and the replacement will be the landing page. Login.jsp.

After running logoutSampleJSP2 running logoutsamplejsp2, you will look back later: • When the user exits, try to click the back button, the browser does not display the protected page, which only reality login page Login.jsp also gives the prompt information session HAS ended • However, when the page returned by the back button is to process the page of the user submitted data, IE and Avant browser will pop up the following information prompt: Warning: The page has expired ... (You must see) After refresh, the previous JSP page will be redisplayed in the browser. Obviously, this is not what we want to see because it violates the purpose of logout action. When this happens, it is likely to be a malicious user attempting to get data from other users. However, this problem only appears in the back button corresponding to a page that handles the POST request. Recording the last login time The above problem occurs because the browser re-submits its data in its cache. In the example of this article, the data contains the username and password. No matter whether security warning information is given, the browser has played a negative role. In order to solve the problems in LogoutSampleJSP2, logoutSampleJSP3's login.jsp contains a hidden form field called LastLogon, which is initialized by a LONG type, based on the hidden form field called LastLogon. This long value is the number of milliseconds since January 1, 1970, called System.CurrentTimeMillis (). When the Form submit in login.jsp, LoginAction.jsp first compares the value in the hidden domain with the values ​​in the user database. The web application considered this is a valid landing only when the value in the LastLogon form field is greater than the value in the database. To verify that the login is logged in, the LastLogon field in the database must be updated in the listLogon value in the form.

In the above, when the browser repeatedly submits the data, the LastLogon value in the form is not larger than the LastLogon value in the database, so LoginAction goes to the login.jsp page, and prompts the session has ended.please log in. Listing 5 is loginaction The code segment of the election: Listing 5 // ... RequestDispatcher Rd = Request.getRequestDispatcher ("HOME.JSP"); // forward to homepage by default // ... if (rs.getstring ("password"). Equals. (password)) {// If valid password long lastLogonDB = rs.getLong ( "lastLogon"); if (lastLogonForm> lastLogonDB) {session.setAttribute ( "User", userName); // Saves username string in the session object stmt .executeUpdate ("Update User Set LastLogon =" LastLogonform "Where username = '" username "'");} else {Request.setttribute ("Error", "Session Has Ended. please login."); RD = request.getRequestDispatcher ( "login.jsp");}} else {// password does not match, ie, invalid user password request.setAttribute ( "Error", "invalid password."); rd = request.getRequestDispatcher ( " Login.jsp ");} // ... rd.Forward (Request, Response); // ... In order to implement the above method, you must record the last login time of each user. This can be easily implemented by adding a LastLogin field by adding a LastLogin field by adding a LastLogin field. LDAP and other security domains need to be slightly movable, but it is obvious that it can be implemented. There are many ways to last login time. Example LogoutSampleJSP3 utilizes the number of milliseconds since January 1, 1970. This method is also possible when many people use a user account in different browsers. Running LogoutSampleJSP3 Run Sample LogoutSampleJSP3 will show how to properly handle exit issues. Once the user exits, click the back button on the browser to be protected on the browser under any circumstances. This example shows how to properly handle exit issues without additional training. In order to make the code more concise, some redundant code can be removed. One way is to write code in Listing 4 to a separate JSP page, and can be referenced by tab other. The exit implementation under the Struts framework is compared to the JSP or JSP / Servlets, and another option is to use Struts. Adding a framework for a Struts-based web app to add a framework for exiting the problem to be elegantly achieved. This part is attributed to Struts to use the MVC design mode to clearly separate the models and views.

In addition, Java is an object-oriented language that supports inheritance, which can be reused easier than scripting in JSP. In Struts, the code in Listing 4 can be transplanted into the Execute () method of the Action class from the JSP page. In addition, we can also define a basic class of inheriting the Struts Action class, which contains the code in Listing 4. By using the class inheritance mechanism, other classes can inherit the general logic in the basic class to set the HTTP header information and retrieve the UserName string in the HTTPSession object. This basic class is an abstract class and defines an abstract method executection (). All subclasses inherited from the base class should implement the exECUTUTUTEAction () method rather than override it.

6 is a partial list of the code base class: Listing 6 public abstract class BaseAction extends Action {public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {response.setHeader ( "Cache-Control", " No-cache "); // forces caches to obtain a new copy of the point from the Origin Server Response.setHeader (" Cache-Control "," No-store "); // Directs Caches Not to Store The page Under Any Circumstance Response.SetDateHeader ("Expires", 0); // Causes the proxy cache to see the page as "stale" response.sethead ("prgma", "no-cache"); // http 1.0 backward Compatibility if (! this.userIsLoggedIn (request)) {ActionErrors errors = new ActionErrors (); errors.add ( "error", new ActionError ( "logon.sessionEnded")); this.saveErrors (request, errors); return mapping.findForward ( " Sessionnded ");} return executection (mapping, form, request, response); } Protected abstract ActionForward executeAction (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException; private boolean userIsLoggedIn (HttpServletRequest request) {if (. Request.getSession () getAttribute ( "User") == null) { Return false;}}}} The code in Listing 6 is very similar in Listing 4, just use ActionMapping Findforward replaces the RequestDispatcher Forward. In Listing 6, if the username string is not found in the httpsession, the ActionMapping object will find the Forward element named sessionended and jump to the corresponding PATH. If found, the subclass will execute its business logic that implements the executection () method.

Therefore, it is necessary to declare a Forward element for all subclauses in the configuration file struts-web.xml. Listing 7 illustrates such a statement in secure1 action: Listing 7 Inherited Sub-class secure1action from the BaseAction class implements the executection () method instead of overwriting it . Secure1Action class does not perform any exit code, as shown in Listing 8: Listing 8public class Secure1Action extends BaseAction {public ActionForward executeAction (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {HttpSession session = request.getSession (); return (Mapping.FindForward ("Success"));}} You only need to define a base class without the need for additional code work, the above solution is elegant and effective. In any case, the common behavioral method is written into a base class that inherits the StrutsAction is a common experience of many Struts projects, which is recommended. Limitularity The above solution is very simple and practical for JSP or Struts-based web applications, but it still has some limitations. In my opinion, these limitations are not critical. Conclusion This paper describes the solution to the resolution, although the program is simple and surprising, but it works effectively in all situations. Whether it is for JSP or Struts, what to do is to write a code that does not exceed 50 rows and a method of logging in the user's last login time. Mixing these programs in web applications can make the private data supported inseparable, while also increased users' experience.

转载请注明原文地址:https://www.9cbs.com/read-103598.html

New Post(0)