The Virtual Shopping Mall (VSM) controls access to application
features by displaying user interfaces based on user roles. For example, shop
owners can access pages that enable them to upload files, but mall customers
cannot. The VSM applies a filter to process user requests and return the appropriate
pages. Using filters, you can add this kind of access control to a JSP-based
application without touching the existing code.
This filter-based access control model is flexible, too, because
the data that maps user roles to specific JSPs is stored in a text file. As
a result, you can modify mappings and leave the application in placethere's
no need to recompile or redeploy. The listing below shows the contents of uiaccesscontroller.properties,
the text file that maps user roles to JSPs for the VSM.
# Home page URI for each role admin.HOME=/adminMainPage owner.HOME=/ownerMainPage user.HOME=/main DEFAULT.LOGIN=/vsmlogin
# Header/footers JSP for each role admin.HEADER=../misc/adminHeader.jsp owner.HEADER=../misc/ownerHeader.jsp DEFAULT.HEADER=../misc/userHeader.jsp user.HEADER=../misc/userHeader.jsp admin.FOOTER=../misc/adminFooter.jsp owner.FOOTER=../misc/adminFooter.jsp DEFAULT.FOOTER=../misc/commonFooter.jsp user.FOOTER=../misc/commonFooter.jsp
# Navigation JSP for each role admin.NAVIGATION=../mallAdmin/leftNavigation.jsp owner.NAVIGATION=../shopOwner/leftNavigation.jsp
The VSM reads from the mapping file when the Access Control
filter is initialized, and uses helper classes UIController and
URIMapping to access the data (you can view
the source code online). Here is a portion of the Java code for the AccessControlFilter
class. The init method gets an instance of the UIController
class, and the doFilter method calls an internal method named checkPrivileges
(a listing follows) to do the main processing for the filter.
...
// Interface to the uiaccesscontroller.properties file private UIController uiController = null;
...
public void init( FilterConfig config ) throws ServletException { this.filterConfig = config; this.uiController = UIController.getInstance(); }
...
public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { try {
// checkPrivileges also uses the uiController attribute
// initialized in the init method.
checkPrivileges( request, response, chain ); } catch( Exception ex ) { throw new ServletException("Error in the doFilter method of "+ "AccessControlFilter class of given status"+ ex.getMessage() ); } } ...
Here is the Java code for AccessControlFilter.checkPrivileges.
This method does the "heavy lifting" for the filter. After getting
the user's role and the URL of the requested page, then checks these values
against the mapping data. If the requested page is appropriate for the user's
role, the code calls chain.doFilter to invoke the page and continue
with normal processing. Otherwise, the code displays an alternate JSP (for example,
to prompt the user to log in), then returns. The code does not call chain.doFilter
in such cases, because the user does not have sufficient privileges to view
the requested JSP.
...
/** * Private helper method to check the access controls * @param <b>request</b> The servlet request object * @param <b>response</b> The servlet response object * @param <b>chain</b> Object representing the chain of all filters * @throws <b>Exception</b> If there was an error while checking the * role privileges */ private void checkPrivileges( ServletRequest request, ServletResponse res, FilterChain chain ) throws Exception { HttpServletRequest req = (HttpServletRequest)request; // Get the session object from the request HttpSession session = req.getSession(); // Get the uri information from the request String uri = req.getPathInfo(); // Get the role of the user String role = (String)session.getAttribute( "role" ); if( role == null ) { role = "DEFAULT"; } // Set the header and footer for default user req.setAttribute( "Header", uiController.getUI( role, "HEADER" ) ); req.setAttribute( "Footer", uiController.getUI( role, "FOOTER"
) ); try { req.setAttribute( "Navigation", uiController.getUI( role, "NAVIGATION" ) ); } catch( Exception ex ) { // If no navigation for this role, skip it } URIMapping info = RequestMap.getInstance().getURIMapping( uri ); // The URI is protected because it has a set of roles associated with it if( info.getRoles() != null && info.getRoles().length > 0 ) { // New session so not logged in yet. Redirect to login page if( session.isNew() ) { Hashtable data = new Hashtable( req.getParameterMap() ); // Set the attribute for session and request session.setAttribute( "_userData", data ); req.setAttribute( "Originator", uri ); // Create the RequestDispatcher RequestDispatcher rd = filterConfig.getServletContext(). getRequestDispatcher( "/" + RequestMap. getInstance().getJsp( uiController.getUI( role, "LOGIN" ) ) ); rd.forward( req, res ); return ; } else { // If not valid, redirect to login page if( !info.isValidRole( role ) ) { Hashtable data = new Hashtable( req.getParameterMap() ); // Set the attribute for session and request session.setAttribute( "_userData", data ); req.setAttribute( "Originator", uri ); // Create the RequestDispatcher RequestDispatcher rd = filterConfig.getServletContext(). getRequestDispatcher( "/" + RequestMap. getInstance().getJsp( uiController.getUI( "DEFAULT", "LOGIN" ) ) ); rd.forward( req, res ); return ; } } } // The privileges are sufficient to invoke this URI, // continue normal processing of the request. chain.doFilter( req, res ); }...
Conclusion
By adding servlet filters to your bag of developer tricks,
you can customize, enhance, and extend Web applications without modifying existing
code. The VSM sample application shows just a few of the ways you can implement
and use filters. Other
possibilities include logging and auditing, image conversion, data compression,
localization, and XSL transformations of XML documents.
Questions or comments? Post a message in the OTN
Sample Code discussion forum or send email to the author.
Extending Servlet Code: Servlet Filters in the VSM
Author: Robert Hall, Oracle Corporation
Date: June 2002
This document is provided for information purposes only and
the information herein is subject to change without notice. Please report any
errors herein to Oracle Corporation. Oracle Corporation does not provide any
warranties covering and specifically disclaims any liability in connection with
this document.
Oracle is a registered trademark and Enabling the Information Age is a trademark
or registered trademark of Oracle Corporation. All other company and product
names mentioned are used for identification purposes only and may be trademarks
of their respective owners.
Oracle Corporation
World Headquarters
500 Oracle Parkway
Redwood Shores, CA 94065
U.S.A.