Redirect to login page when user clicks on back button after logout in JSF [duplicate] - jsf

This question already has answers here:
Avoid back button on JSF web application
(2 answers)
Closed 6 years ago.
When the user clicks on the logout page it takes him to the login.xhtml.Now when the user clicks the back button it is taking him to the page before logout and I am trying to avoid this by using the doFilter which has been mentioned in many posts and my code is:
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
chain.doFilter(req, res);
But it did not work.I also read in one post that if the URL has http then it does not work? Could you suggest how I can avoid this behavior and make the user go to the login page when he clicks on the back button after logout.

I do not know what is the reason of your problem but note that in your web filter you should Skip JSF resources any way the follwing filter is working for me in all .xhtml pages try it
import java.io.IOException;
import javax.faces.application.ResourceHandler;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet Filter implementation class NoCacheFilter
*/
#WebFilter(urlPatterns = {"*.xhtml"})
public class NoCacheFilter implements Filter {
/**
* Default constructor.
*/
public NoCacheFilter() {
// TODO Auto-generated constructor stub
}
/**
* #see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* #see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
/**
* #see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}

Related

How to stop authorization WebFilter from redirecting me to homepage every time I invoke a request from another page

I am trying to build a simple Login/Signup Interface using JSF, Hibernate and WildFly. I have used the following AuthorizationFilter class so far in order to redirect to the login page if the session is not authenticated.
I also implemented a simple User CRUD view called
/admin.xhtml
which manages user entries in the DB. Now my problem is that every time I click a button to CRUD a User entry in admin.xhtml I am automatically redirected to the login page. When I disable this WebFilter everything works perfectly fine with the CRUD Interface.
How can I prevent this WebFilter from redirecting me after I have logged in and created a session?
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
#WebFilter(filterName = "AuthFilter", urlPatterns = { "*.xhtml" })
public class AuthorizationFilter implements Filter {
public AuthorizationFilter() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest reqt = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
HttpSession ses = reqt.getSession(false);
String reqURI = reqt.getRequestURI();
if (reqURI.contains("/login.xhtml")
|| (ses != null && ses.getAttribute("username") != null)
|| reqURI.contains("/public/")
|| reqURI.contains("javax.faces.resource"))
chain.doFilter(request, response);
else
resp.sendRedirect(reqt.getContextPath() + "/faces/login.xhtml");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
#Override
public void destroy() {
}
}

How to implement LogoutFilter?

Hi guys I am building a Java web app using JSF. For authentication I have used Apache Shiro.I have built a logout button which is calling the logout method of shiro and then I redirect the user to login page. But If I click back button the user can navigate into pages. I read about this and I realized that I had to implement my own custom filter. This is the code of the filter :
import al.ikubinfo.ipermit.bpmn.model.entities.UserEntity;
import al.ikubinfo.ipermit.bpmn.services.UserService;
public class LoginFilter implements Filter {
private static final String LOGIN_VIEW = "/login.xhtml";
#EJB
private UserService userService;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
UserEntity currentUser = userService.getCurrentUser();
if (currentUser == null) {
httpServletResponse.sendRedirect(httpServletRequest.getServletContext().getContextPath() + LOGIN_VIEW);
}
else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
}
I have also included it in the web.xml but it doesnt work. The application start successfully but noe view is opened. Can someone help me please?
When using the back button you are seeing a cached version of the page. The page is cached locally in the browser.
After logout you must be going to login page
Use following javascript on this page
var url = window.location.href;
window.history.go(-window.history.length);
window.location.href = url;
Also try to insert
<META Http-Equiv="Cache-Control" Content="no-cache">
<META Http-Equiv="Pragma" Content="no-cache">
<META Http-Equiv="Expires" Content="0">
into jsp pages so that browser dont cache the pages.

Set Http header using Jboss6.1

Is there any way to set HttpHeader using Jboss6.1's configuration file. These configuration is applicable to a whole project.
I want to set bellow properties in Jboss6.1 server using its configuration file.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0);
I tried it with domain.xml but nothing works.
Don't complicate yourself. If you want every response has this header configuration, create your own filter to do this. This way you won't be coupled to JBoss and get what you want.
Here you have a filter sample:
package your.package;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class NoCacheFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse hsr = (HttpServletResponse) res;
hsr.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
hsr.setHeader("Pragma", "no-cache");
hsr.setDateHeader("Expires", 0);
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
then you only have to configure it into your web.xml more or less this way:
<filter>
<filter-name>noCacheFilter</filter-name>
<filter-class>your.package.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noCacheFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This mapping is valid for all request, but you can adapt it.
Hope it helps!

JSF login filter, session is null

I've been trying to follow this answer primarily but I always get redirected to my login.xhtml (except for when i log in from the login page) because this...
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
Is always null.
I've been trying to print out user info on the login screen and no matter how i get there all fields(username, password, loggedIn...) are always null, even if i type the adress straight from the admin page (that's where you get when you log in).
How do I make it so that the session is saved, not whiped everytime i type in the adress manually/leave the page?
AppManager:
import java.io.Serializable;
import javax.ejb.EJB;
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
import jobapp.controller.Controller;
#ManagedBean(name="appManager")
#SessionScoped
public class AppManager implements Serializable {
private static final long serialVersionUID = 16247164405L;
#EJB
private Controller controller;
private String username;
private String password;
private boolean loggedIn;
private Exception failure;
...
/**
*
* #param e an exception to handle.
*/
private void handleException(Exception e) {
e.printStackTrace(System.err);
failure = e;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
/**
* The login method.
* calls the controllers login method.
*
*/
public void login(){
try{
failure = null;
loggedIn = controller.login(username, password);
}catch (Exception e){
handleException(e);
}
}
/**
* The logout method.
* Sets the user's info to null
* and stops the conversation.
*/
public void logout(){
username = null;
password = null;
loggedIn = false;
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
}
...
Filter:
#WebFilter("/faces/admin.xhtml")
public class LoginFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//TODO fix "am" nullpointer
AppManager am = (AppManager) req.getSession().getAttribute("appManager");
if (am != null && am.isLoggedIn()) {
// User is logged in, so just continue request.
chain.doFilter(request, response);
} else {
// User is not logged in, so redirect to login.
HttpServletResponse res = (HttpServletResponse) response;
res.sendRedirect(req.getContextPath() + "/faces/login.xhtml");
}
}
#SessionScoped is from javax.enterprise.context.SessionScoped
This one works in combination with CDI #Named only. As you're using JSF #ManagedBean, you should be using the scope annotations from javax.faces.bean package instead.
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class AppManager implements Serializable {
Without a valid scope, a JSF managed bean would behave like #RequestScoped which effectively means that it's constructed again and again on every request.

JSF 2.1 Redirect Preserving error message

I have the following commandButton action method handler:
public String reject()
{
//Do something
addMessage(null, "rejectAmountInvalid", FacesMessage.SEVERITY_ERROR);
redirectToPortlet("/xxx/inbox?source=pendingActions#pendingApproval");
}
public static void addMessage(String clientId, String key, Severity level, Object... objArr)
{
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage message = null;
String msg = getTextFromResourceBundle(key);
if (objArr != null && objArr.length > 0)
msg = MessageFormat.format(msg, objArr);
message = new FacesMessage(msg);
message.setSeverity(level);
context.addMessage(clientId, message);
}
public static void redirectToPortlet(String urlToRedirect)
{
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
try
{
PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
ThemeDisplay themeDisplay = (ThemeDisplay) portletRequest.getAttribute("THEME_DISPLAY");
String portalURL = themeDisplay.getPortalURL();
String redirect = portalURL + urlToRedirect;
externalContext.redirect(redirect);
}
catch (Throwable e)
{
logger.log("Exception in redirectToPortlet to the URL: " + urlToRedirect, VLevel.ERROR, e);
}
}
When the page is redirected to "/xxx/inbox?source=pendingActions#pendingApproval", the error message I added is lost. Is there a way to preserve the error message in JSF 2.1?
Thanks
Sri
You can use a PhaseListener to save the messages that weren't displayed for the next request.
I've been using for a while one from Lincoln Baxter's blog post Persist and pass FacesMessages over multiple page redirects, you just copy the class to some package and register on your faces-config.xml.
It's not mentioned explicitly in the blog post, but I'm assuming the code is public domain, so I am posting here for a more self-contained answer:
package com.yoursite.jsf;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
/**
* Enables messages to be rendered on different pages from which they were set.
*
* After each phase where messages may be added, this moves the messages
* from the page-scoped FacesContext to the session-scoped session map.
*
* Before messages are rendered, this moves the messages from the
* session-scoped session map back to the page-scoped FacesContext.
*
* Only global messages, not associated with a particular component, are
* moved. Component messages cannot be rendered on pages other than the one on
* which they were added.
*
* To enable multi-page messages support, add a <code>lifecycle</code> block to your
* faces-config.xml file. That block should contain a single
* <code>phase-listener</code> block containing the fully-qualified classname
* of this file.
*
* #author Jesse Wilson jesse[AT]odel.on.ca
* #secondaryAuthor Lincoln Baxter III lincoln[AT]ocpsoft.com
*/
public class MultiPageMessagesSupport implements PhaseListener
{
private static final long serialVersionUID = 1250469273857785274L;
private static final String sessionToken = "MULTI_PAGE_MESSAGES_SUPPORT";
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
/*
* Check to see if we are "naturally" in the RENDER_RESPONSE phase. If we
* have arrived here and the response is already complete, then the page is
* not going to show up: don't display messages yet.
*/
// TODO: Blog this (MultiPageMessagesSupport)
public void beforePhase(final PhaseEvent event)
{
FacesContext facesContext = event.getFacesContext();
this.saveMessages(facesContext);
if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
{
if (!facesContext.getResponseComplete())
{
this.restoreMessages(facesContext);
}
}
}
/*
* Save messages into the session after every phase.
*/
public void afterPhase(final PhaseEvent event)
{
if (!PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
{
FacesContext facesContext = event.getFacesContext();
this.saveMessages(facesContext);
}
}
#SuppressWarnings("unchecked")
private int saveMessages(final FacesContext facesContext)
{
List<FacesMessage> messages = new ArrayList<FacesMessage>();
for (Iterator<FacesMessage> iter = facesContext.getMessages(null); iter.hasNext();)
{
messages.add(iter.next());
iter.remove();
}
if (messages.size() == 0)
{
return 0;
}
Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
List<FacesMessage> existingMessages = (List<FacesMessage>) sessionMap.get(sessionToken);
if (existingMessages != null)
{
existingMessages.addAll(messages);
}
else
{
sessionMap.put(sessionToken, messages);
}
return messages.size();
}
#SuppressWarnings("unchecked")
private int restoreMessages(final FacesContext facesContext)
{
Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
List<FacesMessage> messages = (List<FacesMessage>) sessionMap.remove(sessionToken);
if (messages == null)
{
return 0;
}
int restoredCount = messages.size();
for (Object element : messages)
{
facesContext.addMessage(null, (FacesMessage) element);
}
return restoredCount;
}
}
And then, on your faces-config.xml:
<phase-listener>com.yoursite.jsf.MultiPageMessagesSupport</phase-listener>
If the redirect is to the same path, you could just use Flash#setKeepMessages().
context.getExternalContext().getFlash().setKeepMessages(true);
This way the messages are persisted in the flash scope which lives effectively as long as a single subsequent GET request (as occurs during a redirect).

Resources