I am using the <logic resent> tag to determine if a user is logged in or not on my JSP's. If the user is not logged in, I redirect to the Login Page. Upon successful login, I need to get back to the page the user wanted to go to in the first place. I know how to do this without using STRUTS, but I don't know how to do it the STRUTS way. Thanks.
One way I thought about doing this was in the logic tag where I go to the Login Page, put a session variable out there that contains the page I Am leaving. After I login, I use the mapping to find a forward to a Servlet where I check for that Session variable. If it is there, I go to that page, if it is not there, return to the Home or index.jsp page. The only problem I see with that is I have almost added an extra controller servlet. I am hoping there is a cleaner approach for this.
I know how to do this without using STRUTS, but I don't know how to do it the STRUTS way. I don't know which of the various solutions to this problem you "know how to do without using STRUTS", but it worries me to think that you might be suggesting putting some sort of authentication code into every JSP I usually prefer to do this with a filter "in front of" the rest of the application. This is completely independent of how the actual application is written, and should work as well with Struts as with any other way of writing a web app. Or is that somehow not appropriate either?
Maybe I'm confused Gregg, but the determination of whether or not a user is logged in should be taking place in the action, not in the jsp. Since all user requests should be going through the controller, jsp's should never have to be called directly. Your above example is in violation of this principle. [ October 22, 2003: Message edited by: Jason Menard ]
Ok, so set me straight guys. I guess I am not getting it. JSPs are being called directly. I have an AddReference.jsp. I have a menu bar with a link to that page. The user should only be able to access this page if he/she is logged in. I have an Action class that does whatever needs to be done with this form. I guess I don't know what you mean by jsp's should never be called directly.
In MVC, all user requests should go through the control. In the case of Struts, the control is your ActionServlet. When you call AddReference.jsp directly, your request is not being made to the control. Instead you should be making a call to something like AddReference.do, which uses the action handling the application logic, which in turn would forward to AddReference.jsp as the view if the Action determined that was the correct course of action (which it might not be if the user wasn't logged in for example). There really shouldn't be all that much in the way of logic inside your view (jsp). Maybe you'll have some minor view logic in there to determine whether or not to show part of the page, or whether or not a certain field should be editable, but that's really about it. All your application logic should reside in your Actions. And by application logic, I mean application controlling the flow of your application. And of course your business logic should all be handled in your business objects (java beans for example). So let's say you want to display the results of a database query. You click a link which calls the appropriate action (/myAction.do). First the Action checks to see if you are logged in, and if not it tells the ActionServlet to send you to the login page. Barring that, the action determines that a business object needs to be instantiated, and its getResults() method called, returning a List of some object which encapsulates your result data. The business object or its delegate makes the database call and returns the List of results. The Action places that list in some scope (probably request scope in this case) where it will be made available to the view (your jsp). If all is right with the world, the Action tells the ActionServlet that the user should be forwarded to the jsp used to display your query results. The jsp simply iterates through the results of the List that was made available by the Action and displays them. Maybe it contains some minor view logic where it displays "no results returned" if the List was empty or null. I'm sorry if I'm breaking it down to simplistically, I just want to make sure we're on the same page. Since this si the general flow though, you can see that there's no reason a user should be calling a jsp directly, and in fact that kind of defeats the whole purpose of using struts in most cases.
I'm sorry if I'm breaking it down to simplistically, Don't be sorry. I need it to be simple. So let's say you want to display the results of a database query. You click a link which calls the appropriate action (/myAction.do). First the Action checks to see if you are logged in, and if not it tells the ActionServlet to send you to the login page. Barring that, .... Ok, I understand that. But it still isn't clear as to why you would not call a JSP directly when all you are really doing is displaying a Form. There is no business logic yet. The only logic in this page is whether or not the user is logged in. AddReference.jsp is a Form for someone to input their reference. Let me run down my logic for you real quick, and maybe we can get this cleared up. I click on Add Reference which takes me to AddReference.jsp - This is simply a form for the user to input some reference data. I click on submit - This calls my AddReferenceAction which uses some classes to store the information in the database. If this happened successfully, my AddReferenceAction finds the forward for "valid" and forwards back to the AddReferece.jsp page waiting for another entry. If something went wrong, I find the forward for "invalid" and I forward to an error page. But what you are saying is I should have another Action class that determines if I am logged in or not and then forwards either to AddReference.jsp or Login.jsp?
Ok, I understand that. But it still isn't clear as to why you would not call a JSP directly when all you are really doing is displaying a Form. There is no business logic yet. You can physically do anything you want of curse, but just keep in mind that if you are calling a jsp directly, then you are ditching MVC and defeating the purpose of using struts, as well as losing out on many of its benefits. Your user request is not going through your controller and you have now divulged underlying protions of your architecture to your users unecessarily. If you want to simply forward to a jsp, then in your struts-cnfig simply declare the "type" to be org.apache.struts.actions.ForwardAction. This leaves you with the benefits that struts provides, such as allowing that page to be mapped to a global forward (very convenient in many instances), keeping the user requests going through the ActionServlet, etc... The only logic in this page is whether or not the user is logged in. Which technically is application logic, not something you would want to be controlling in the view. Now of course it seems very anal to try to strictly adhere to MVC like this, but these things are after all "best practices". Not to mention, you are now stating that in 100% of all cases, that view always requires that particular application logic be executed, as opposed to having your view be something that may potentially be forwarded to by multiple actions, where maybe that logic condition does not hold in all cases. It keeps the view a bit more generic. But what you are saying is I should have another Action class that determines if I am logged in or not and then forwards either to AddReference.jsp or Login.jsp? Potentially. Let's say you always want to check that a user is logged in each time they submit a request. In such a case, you may want to have a base Action class containing this functionality which all your Actions will subclass. The template-method pattern works good here. Here's an example: Your base Action class:
An example of a specific Action class extending BaseAction:
So the idea being that your actions extend BaseAction if appropriate, and you simply write the run() method for each action. In that way, you can place all common functionality in the execute() method of your base Action class, and all the specific functionality in separate classes. [ October 22, 2003: Message edited by: Jason Menard ]
Ok, it's beginning to sync in. Just be patient with me while I grasp all this. I am understanding what you are saying. Here is my bit-o-confusion. If I made an Action to display my AddReference.jps page, all that action will do is forward to that JSP page. To me, it seems like a wasted step. I understand WHY MVC wants it done this way. But to make a class that does:
I mean, seriously, that is all that class would do. [ October 22, 2003: Message edited by: Gregg Bolinger ]
Originally posted by Gregg Bolinger: I mean, seriously, that is all that class would do.
And that's essentially all org.apache.struts.actions.ForwardAction does (although it uses the "parameter" attribute to determine where to forward to). The difference is that now you've created a ForwardAction specific to your application. This action can be used multiple places in yourr app. For example:
Just have that action always return mapping.findForward("success") or something. Now you've made it so that every JSP you want to display first checks to see if the user is logged in. [ October 22, 2003: Message edited by: Jason Menard ]
Jason, I wanted to say thanks again for being so patient with me. I implemented what you suggested and it worked perfectly. Not only that, but it solved another design mistake as well. On each form I will have some Drop Down lists that need to be populated from the database. I was originally subclassing ActionServlet in a class of my own and putting all the Objects into the servletContext(). I know, bad idea. But it worked. But with your suggestion, since I have an initial Action forwarding to the view, I can pull the data from the DB and put them in the request scope and use them that way. Saves some overhead of having to clean up the servletContext. Thanks a bunch. However, my initial question still remains. The fact of the matter is, someone can still manually type in http://address/holocron_struts/users/AddReference.jsp, and I still need to check if the user is logged in before displaying this page. And I still need to get back to that page after the user has logged in. Thanks.
I'm glad it's working out for you. A couple of things... While it may be possible for someone to type that address in manually, how will they know it? If all your requests go through the controller, and there is no direct reference to that page anywhere, how will they know to type it in? Your application will never expose it, as all the user will see are something along the lines of *.do or /do/* type urls. So assuming that your app is designed so that all requests are supposed to go through the controller, and assuming that somehow they are able to come up with a direct address to a jsp in the program, why would you want to re-inforce the behavior of linking directly to a jsp by allowing them to go directly back to it after they login, instead of forwarding them to the beginning of the app? Philisophical issues aside, request.getHeader("referer") should get you the info you need. It will return the absolute url of the calling page. Of course then you would have to parse out that url and equate it to an action. Another thing you could do is place a hidden form parameter on each JSP page containing the name of the page (not the name of the jsp though), which you could lookup and equate to a physical Action programmatically. This would normally only be read when the page is submitted. But you can also do something like the following: AddReference.jsp
While it may be possible for someone to type that address in manually, how will they know it? I actually thought of that a while after I posted. But I wanted to wait and see what you said. why would you want to re-inforce the behavior of linking directly to a jsp by allowing them to go directly back to it after they login, instead of forwarding them to the beginning of the app? It's not so much an issue of calling the JSP page directly (now that you have shown me the light ) I guess as it is with my session timeout. My session will expire after 30 minutes. So here is a scenerio. The user has logged in, they are working with the web app. They go to a form, and they get called away. An hour later they come back to that form and hit submit. Since the session has expired, they are taken to the login page. After they have logged in correctly, wouldn't the desired action be to take them back to the form where they came from? I assumed this was a common design. If it is not, I have no problems taking the user back to the beginning of the web app. Thanks for the help. [ October 24, 2003: Message edited by: Gregg Bolinger ]
I don't think that is an uncommon design. On one of the larger struts apps I've worked on, we set the timeout for 60 minutes, and allowed the user to save their work in progress in case they wanted to start something and then finish it later. Of course while that design made sense for our app, it may very well make sense for you to just have them log in again and send them back to where they were when they timed out. Another design might have it wait until they hit submit, and if they timed out, forward to login, then after they login, forward the data they submitted to the original action they intended to call. The getURI() or getURL() methods of HttpRequest might help you in the latter case.