ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Jakarta Struts: Seven Lessons from the Trenches
Pages: 1, 2, 3, 4

4. Protect JSPs Behind WEB-INF

To better protect your JavaServer Pages from unauthorized access or viewing, it's a good idea to store your pages in a directory that is below the Web application's WEB-INF directory.



It's very typical for JSP developers to keep their pages in subdirectories under the Web application root. For example, Figure 2 shows a typical directory structure for a storefront application. The JSPs relating to catalog are placed in the catalog subdirectory under the storefront directory. The same might be true for the customer JSPs, order JSPs, and so on.

Figure 2. JSPs are placed into separate directories based on functionality.


The problem with this approach is that these pages are a little more susceptible to a user being able to view the source of the JSPs, or at least call the JSP directly. In some cases, this might not be a huge issue, but under certain circumstances it can be a security risk. It could also present a problem if users are allowed to circumvent the Struts controller by invoking a JSP directly.

To reduce this risk, you can move the pages into a directory underneath WEB-INF. Based on the Servlet specification, WEB-INF is not part of the public document tree of the Web application. Therefore, no resource within the WEB-INF directory (nor those beneath it) may be served directly to a client. We can still use JSPs stored underneath the WEB-INF to render views for a client; however, a client may not request one of the JSPs directly. This helps to protect your site from unwanted access and at the same time, allows you to render views using JSPs.

Using the previous example, the directory would like the one in Figure 3, after the JSPs are moved into a directory called JSP underneath the WEB-INF directory.

Figure 3. The JSPs are more secure underneath the WEB-INF directory.


Once the JSPs are located underneath the WEB-INF directory, you must use "WEB-INF" as part of the URL when referencing the pages. For example, suppose we had an Action mapping in our Struts configuration file for a logoff action. The paths to JSPs must include WEB-INF at the beginning.

<action
  path="/logoff"
  type="org.apache.struts.webapp.example.LogoffAction">
  <forward name="success" path="/WEB-INF/jsp/index.jsp"/>
</action>

The only trick with using this approach, which is good practice with Struts in any case, is that you should always front your JSPs with a Struts action. Even if the Action is a very basic JSP, you should always call an Action that in turn invokes the JSP.

A final comment when storing your JSPs underneath WEB-INF: not all containers support this feature. Earlier versions of WebLogic did not interpret the Servlet specification the same as others, and it was not possible to do this. This is reported to be changed with newer versions of WebLogic. Just be sure to check your specific container.

5. Use the Prebuilt Actions

The Struts framework comes with several prebuilt Action classes that can save a tremendous amount of development time. The most beneficial of these are the org.apache.struts.actions.ForwardAction and the org.apache.struts.actions.DispatchAction.

Using the ForwardAction

There are probably many cases in your application where you want an Action to just forward to a JSP. In fact, the previous tip stated that it's good practice to always front a JSP with an Action. If you have the case where you don't need to perform any logic in the Action but would like to follow the convention of going through an Action to access a JSP, the ForwardAction can save you from creating many empty Action classes. The benefit of the ForwardAction is that you don't have to create an Action class of your own. All you have to do is to declaratively configure an Action mapping in your Struts configuration file.

For example, suppose that you had a JSP called index.jsp and instead of calling this page directly, you would rather have the application go through an Action class. What you can do is set up an Action mapping like this:

<action
   path="/home"
   parameter="/index.jsp"
   type="org.apache.struts.actions.ForwardAction"   
   scope="request"      
   validate="false">  
</action>

When the home action is invoked, the ForwardAction performs a forward to the index.jsp page.

While we are discussing forwarding without having to provide an Action class, it should also be mentioned that you could also use the forward attribute of the <action> element to achieve the same behavior. The <action> element would look like this:

<action
   path="/home"
   forward="/index.jsp">
</action>

Both approaches save you time and help to reduce the number of files needed by an application.

Using the DispatchAction

The DispatchAction is another Action that is included with the framework that saves a tremendous amount of development time. Instead of providing a single execute() method per Action class (and thus tying one Action to one business method), the DispatchAction allows you to encode several business-related methods within a single Action class. By doing this, the number of Action classes can be reduced and the related business methods can be grouped together, which can make maintenance somewhat easier.

To use the DispatchAction functionality, you need to create a class that extends the abstract DispatchAction. For each business method that you want to provide, you need to provide a method with a particular method signature. If for example, you had a method that you wanted to call to add items to the user's shopping cart, we could create a class called ShoppingCartDispatchAction that had the following method:

public ActionForward addItem( ActionMapping mapping, 
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
  throws Exception;

This class would probably also have a deleteItem() method, a clearCart() method, and others. So instead of creating different Action classes for each of these, we can combine them into a single Action class.

To invoke one of the methods in the ShoppingCartDispatchAction, just include a parameter in the URL that matches one of the method names. So, to invoke the addItem() method, the URL would look something like:

http://myhost/storefront/action/cart?method=addItem

The parameter named method identifies the method to invoke within the ShoppingCartDispatchAction. The name of the parameter can be configured to be just about anything you want. The one used here, "method," is just an example. You configure it within the Struts configuration file.

Pages: 1, 2, 3, 4

Next Pagearrow