简体   繁体   中英

Caching Headers Interceptor does nothing - struts2

I'm developing a web application using Struts2. The user logs in, places a request and then logs out.

When the user clicks the 'Back' button(after logging out), the previous logged-in page should not be visible to him which means I want to disallow browser caching. I've added an interceptor for this purpose:

public class CachingHeadersInterceptor extends AbstractInterceptor{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        // TODO Auto-generated method stub

        final ActionContext context = invocation.getInvocationContext();
        HttpServletResponse response = (HttpServletResponse)context.get(StrutsStatics.HTTP_RESPONSE);
        if(response!=null){
            response.setHeader("Cache-control", "no-cache, no-store");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "-1");

        }

        return invocation.invoke();
    }

}

And this entry in the struts.xml file :

 <interceptors>

       <interceptor name="cachingHeadersInterceptor" class="com.proconsulto.interceptor.CachingHeadersInterceptor"/>
       <interceptor-stack name="defaultSecurityStack">
       <interceptor-ref name="defaultStack"/>
       <interceptor-ref name="cachingHeadersInterceptor"/>
       </interceptor-stack>

       </interceptors>

But after logging out when I click on the Back button, I'm still able to access that logged-in page.

What is my code missing here? I've written this code following the tutorials online.

Here is the exception trace:

WARNING: Unable to load config class com.proconsulto.interceptor.CachingHeadersInterceptor at interceptor - file:/C:/Users/AnkitaNallana/Desktop/OneMoreTime/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ProConsulto%20-%20Everything%20is%20fine%20-%20v16/WEB-INF/classes/struts.xml:21:117 probably due to a missing jar, which might be fine if you never plan to use the cachingHeadersInterceptor interceptor
Jul 08, 2014 3:21:26 PM com.opensymphony.xwork2.util.logging.commons.CommonsLogger error
SEVERE: Actual exception
Caught Exception while registering Interceptor class com.proconsulto.interceptor.CachingHeadersInterceptor - interceptor - file:/C:/Users/AnkitaNallana/Desktop/OneMoreTime/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ProConsulto%20-%20Everything%20is%20fine%20-%20v16/WEB-INF/classes/struts.xml:21:117
    at org.apache.struts2.impl.StrutsObjectFactory.buildInterceptor(StrutsObjectFactory.java:77)
    at com.opensymphony.xwork2.config.providers.InterceptorBuilder.constructInterceptorReference(InterceptorBuilder.java:70)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.lookupInterceptorReference(XmlConfigurationProvider.java:1101)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStack(XmlConfigurationProvider.java:919)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptorStacks(XmlConfigurationProvider.java:932)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadInterceptors(XmlConfigurationProvider.java:955)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:524)
    at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:292)
    at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:112)
    at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:250)
    at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
    at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:429)
    at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:473)
    at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:273)
    at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:254)
    at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:372)
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:98)
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4584)
    at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5262)
    at org.apache.catalina.core.StandardContext$2.call(StandardContext.java:5257)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.ClassNotFoundException: com.proconsulto.interceptor.CachingHeadersInterceptor
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1678)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1523)
    at com.opensymphony.xwork2.util.ClassLoaderUtil.loadClass(ClassLoaderUtil.java:152)
    at com.opensymphony.xwork2.ObjectFactory.getClassInstance(ObjectFactory.java:108)
    at com.opensymphony.xwork2.ObjectFactory.buildBean(ObjectFactory.java:161)
    at com.opensymphony.xwork2.ObjectFactory.buildBean(ObjectFactory.java:151)
    at org.apache.struts2.impl.StrutsObjectFactory.buildInterceptor(StrutsObjectFactory.java:52)
    ... 26 more

To be extra sure I copied & pasted the package & the class name a dozen times, I still don't know why I'm getting a ClassNotFoundException !

The other method would be writing it as JSP <% response.setHeader("xxx","vvv") %> tags on every page. That'd be extremely tedious. I wouldn't want to disable it using JS because that would be bad UX.

I've also noticed another thing. When I did use the <% response.setHeader("xxx","vvv") %> tags on a few JSPs, and clicked the 'Back' button, a Reload button would show up (on Chrome) - if you click on it - the login data gets submitted and one can view the logged-in pages again. What can I do so that this login data is not stored for re-submission?

If there's a similar question which I probably may have not come across - please do mention its link in the comment. I could not find an answer so I'm asking here!

Examples always demonstrate better than theory...

EDIT : I am just showing you a demo.

package com.interceptors;

import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class CachingHeadersInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;

public String intercept(ActionInvocation invocation) throws Exception {

    if (ServletActionContext.getResponse() != null) {
        ServletActionContext.getResponse().setHeader("Cache-control",
                "no-cache, no-store, must-revalidate");
        ServletActionContext.getResponse().setHeader("Pragma", "no-cache");
        ServletActionContext.getResponse().setHeader("Expires", "-1");
        ServletActionContext.getResponse().setHeader("Vary", "*");
    }
    return invocation.invoke();
}

}

In struts.xml

<package name="helloworld" namespace="" extends="struts-default">
   <interceptors>
     <interceptor name="cachingHeadersInterceptor" class="com.interceptors.CachingHeadersInterceptor"/>
     <interceptor-stack name="defaultSecurityStack">
         <interceptor-ref name="defaultStack"/>
         <interceptor-ref name="cachingHeadersInterceptor"/>
     </interceptor-stack>
   </interceptors>
   <action name="login" class="com.common.LoginAction" >
         <interceptor-ref name="defaultStack"/>          
         <interceptor-ref name="cachingHeadersInterceptor"/>

        <result name="success">/Home.jsp</result>
   </action>
  </package>

Output: This is in response header

缓存头输出

And after logout if you want to block user from viewing page you can implement Authorizeinterceptor

Reference : See example of AuthorizationInterceptor.java

In this interceptor just check session value for example username which after logout will be null and if null redirect to login.

You can either create new interceptor or can put the below code in same CachingHeadersInterceptor.java

SessionMap<String,Object> map = (SessionMap<String,Object>) inv.getInvocationContext().getSession();
Object user = map.get("username");  
if(user==null ||user.equals("") || map.isEmpty() || map == null ){  
  return "login";   
}

In struts.xml Define login as result that redirects to login page.

<global-results>
    <result name="login">login.jsp</result>
</global-results>

Also see LoginAction.java and LogoutAction.java in which I have added and removed username from session.

It's Simple.... :)

Have you put below in your html head tag:

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Pragma" content="No-cache" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Expires" content="0" />

Mean while make sure you have removed session after logout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM