I've got a project which is divided in different modules, you have for example a site and a forum.
The forum can be found at:
http://example.com/[forum]/
and for example can be:
http://example.com/support/
http://example.com/helpme/
http://example.com/aforum/
The site can be found at:
http://example.com/[site]/
and for example can be:
http://example.com/site1/
http://example.com/nice/
http://example.com/something/
The [forum] and [site] part are variable. In my database i lookup that "nice" is a site, "helpme" is a forum.
I have a spring RequestMapping for my ForumController:
#RequestMapping(value = { "/{simpleTitle:[0-9a-z-]+}" }, method = RequestMethod.GET, produces = "text/html")
public void list(#PathVariable String simpleTitle, Model model, HttpServletRequest req, HttpServletResponse resp) {
I have the samething for sites, so a SiteController:
#RequestMapping(value = { "/{simpleTitle:[0-9a-z-]+}" }, method = RequestMethod.GET, produces = "text/html")
public void list(#PathVariable String simpleTitle, Model model, HttpServletRequest req, HttpServletResponse resp) {
This of course goes bad, cause 2 controllers with the same requestmapping isn't good.
I can create a FrontController which with above request mapping, lookup what simpleTitle is (a forum or a site) and call functions to display a forum or a site. That works.
But it isn't very "spring" like and structured.
Is it possible "intercept" a request and internally forward (or call the function) on the controller myself?
This way i could have Interceptor which looks a simpleTitle, decides whether it is a forum or site, and "forwards"/"calls" the right controller.
Frankly I like #Luiggi Mendoza solution, but if you want an alternative, use something like this:
package eu.europa.acer.aris.ceremp.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
#Component(value = "yourCustomFilter")
public class YourCustomFilter extends OncePerRequestFilter{
private static final Logger logger = LoggerFactory.getLogger(YourCustomFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//String[] path = request.getRequestURL().toString().split("/");
if (letPagePass(request.getRequestURL().toString()) == false)
{
// if request is bound to static resource like js//img do nothing, the filter chain will activate
if (letResourcePass(request.getRequestURL().toString()))
{
}
else
{
String[] urlInfos = obtainUrlAndParametersLast(request.getRequestURL().toString());
// last element will always give back last part including any parameter
// first element will always be a controller modifier
response.sendRedirect(request.getContextPath()+rebuildControllerPath(urlInfos));
return;
}
}
filterChain.doFilter(request, response);
}
private String rebuildControllerPath(String[] pathElement )
{
//do your thing here
if ("forum".equals(pathElement[0]))
{
String addenda = "/forumController/";
for (String singlePart: pathElement)
{
addenda = addenda+singlePart+"/";
}
return addenda;
}
}
// bind forceful redirect
public boolean letPagePass(String url)
{
// if you have some page that are naturally unique among controllers that you want always to process natively
String[] path = url.split("/");
if (path[path.length-2].startsWith("yourCertainUrlIgnoringParameters"))
{
return true;
}
// directcall
else if (path[path.length-2].startsWith("yourCertainUrlIgnoringParameters2"))
{
return true;
}
else
{
return false;
}
}
public boolean letResourcePass(String url)
{
String[] path = url.split("/");
/*
this assumes you have always a strict structure so your image//js//reource will always be in
https://domainname/a/lot/of/folder/img/actuaresource.png
or
https://domainname/a/lot/of/folder/js/actuaresource.js
etc
*/
//image pass
if (path[path.length-2].equals("img") || url.contains("/img/"))
{
return true;
}
//css pass
else if (path[path.length-2].equals("css") || url.contains("/css/"))
{
return true;
}
//js pass
else if (path[path.length-2].equals("js") || url.contains("/js/"))
{
return true;
}
else
{
return false;
}
}
#Override
public void destroy() {
}
}
and add to your web.xml file the following xml snippet
<!-- your fi Filter -->
<filter>
<filter-name>yourCustomFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>yourCustomFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Cheers Luiggi Mendoza and witchedwiz for the great ideas!
While i was eating i came up with a very simple solution: use servlet filter. Add a request header with a HttpServletRequestWrapper (type: forum or type: site) inside the doFilter.
In the #RequestMapping add a headers property like headers = "type=forum".
Now #RequestMapping can have the same urls, they differ in request header. And all spring functionality works, although i only made a simple test case so far.
WebApplicationContextUtils helped to get spring beans in the servlet filter.
Related
I would like my HandlerInterceptor, in my spring boot application, not to run on requests coming in on the management port.
management.port = 9091
I can think of 2 ways to do it, but i'm looking for a more standard way.
One will be to check the port from within the HandlerInterceptor:
#Override
public boolean preHandle(#NonNull HttpServletRequest request, #NonNull HttpServletResponse response, #NonNull Object handler) {
if(request.getLocalPort() == managementPort){
return true;
}
else{
....
}
}
The second will be to exclude all paths, related to the managementPort when registering the interceptor:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).excludePathPatterns(managementPortEndpoints);
}
This can easily get out of sync.
Is there a more native way to achieve it? (spring configuration of some sort)
I choose javax.servlet.Filter for filtering requests.
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class BlockFilter implements Filter {
private int managementPort = 9091;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request.getRemotePort() == managementPort) {
chain.doFilter(request, response);
} else {
((HttpServletResponse) response).setStatus(401);
}
}
}
Once all accesses to management.port are requests made for URLs that start with /actuator - spring will not run the filters and interceptors on the requests.
So, that seems like the way to go about it
A request to an Action can be validated using the Interceptors. Also, Direct request to a JSP page can be avoided using an empty action declaration. It is something like this;
<action name="home" >
<result>home.jsp</result>
</action>
I want to validate this calling to the JSP page. As I feel that a simple approach can be adding an Action (ActionSupport) with an Interceptor which checks the action name( and do some validation using session etc). But I've a doubt that whether it reduces the performance,because that action class doesn't do anything and just execute its execute() only(useless task...), and where there should be an empty Action .(BUT: as I ve read some docs on Struts2, it is said that even though we don't add an Action calss,the framework itself adds and action class which returns "success" therefore,adding an action class or not ourselves, doesn't affect newly )
Any way, I d like to know what your best approaches are to validate or authorized access to some JSP pages.( number of pages can be many.. not only to one jsp page)
Added:
Example:
Lets say that, there are some restricted pages where all users can't have access,for example user's account page can be visited only to logged in users.There can be more such type of pages. If a request comes to a such page,the user has to be validated.Then, if the request comes through a empty/anonymous action (as explained in above code snip -only action name-no real class) how to validate such requests to JSP pages? Should an action class be used for this?
If your attention is to secure some part of your application so as only Authenticated as well authorize use can access that part, than you have two option
Use an interceptor based authentication
User a security API like Spring -security
Interceptor based authentication is quite easy. here is an example how to do this, but such authentication is not recommended for a production based and real life application since its really a very simple case.
if you are looking for a complete authentication system, i suggest you to look at Spring security.Its quite easy and configurable, all you need to tell the underlying spring mechanism which all areas and under secure tag and Spring security will intercept them before your action get called and only successful and authorize action will get called by spring security.
//This is for authorization
package com.kogent.action;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.ng.ExecuteOperations;
import org.apache.struts2.dispatcher.ng.InitOperations;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.dispatcher.ng.filter.FilterHostConfig;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
public class SessionController extends StrutsPrepareAndExecuteFilter {
protected PrepareOperations prepare;
protected ExecuteOperations execute;
protected List<Pattern> excludedPatterns = null;
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
prepare = new PrepareOperations(filterConfig.getServletContext(),
dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(),
dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
postInit(dispatcher, filterConfig);
} finally {
init.cleanup();
}
}
/**
* Callback for post initialization
*/
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null
&& prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request,
response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(
request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
//here you have to identify the whether the user have access to requested resource or not
//allow him if he was access.
//if(someCondition)
execute.executeAction(request, response, mapping);
//else{
//redirect the user how do you want it to be.
ActionMapping modfiedActionMapping = new ActionMapping();
modfiedActionMapping.setName("someActionName");
modfiedActionMapping.setNamespace("someNameSpace");
execute.executeAction(request, response, modfiedActionMapping);
//}
}
}
} finally {
prepare.cleanupRequest(request);
}
}
public void destroy() {
prepare.cleanupDispatcher();
}
}
<filter>
<filter-name>struts2</filter-name>
<filter-class>Point to your customized filter</filter-class>
</filter>
To provide proper browser caching I want to get rid of the conversationContext parameter, that Apache MyFaces Orchestra adds to every request, for requests to css files.
As Bozho suggested, I've implemented a filter that sets the attribute Orchestra is looking for.
public class ResourceFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException {
if(shouldNotAppendConversation(request)) {
request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE);
}
theChain.doFilter(request, theResponse);
}
private boolean shouldNotAppendConversation(ServletRequest theRequest) {
HttpServletRequest aRequest = (HttpServletRequest) theRequest;
String aPath = aRequest.getRequestURI();
if(aPath.endsWith(".css.jsf")) {
return true;
}
return false;
}
#Override
public void init(FilterConfig theFilterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
That doesn't work the parameter is still appended to every request. While debugging, I've found out that the filter gets first hit by a request to the jsf site. For sure I want to include the conversation context in that request, so the filter forwards the request directly to the next filter in the chain. The next request that hits the filter (usually the request for a css file) has already the conversation context included in the request.
The strange thing is, if I modify the filter to always set the attribute, all request will not have the conversation context attribute. But that means, the conversation context is also not included in the request for the jsf site (but should).
I've noticed that the links to css files in the generated html of the jsf site also contains the conversation context attribute or not depending on the filter implementation. I guess for this reason the second request has already included the conversation context parameter?
I don't understand why Orchestra is appending the conversation context parameter to every request and not just for the requests where the attribute is not set.
How can I implement the filter to work correctly?
The next request (e.g. for a CSS file) hitting your filter after the request to your page has already the conversationContext parameter included just because this is how the url for this resource has been rendered by the page in the previous request.
So the control over conversationContext should be taken at render time. The following solution is working for me with JSF 2 (I am using Mojarra 2.1.11, myfaces-orchestra-core20 1.5, RichFaces 4.1.0.Final). A special servlet filter is doing nothing but wraps HttpServletResponse with our own wrapper:
public class RfOrchestraParamControlFilter implements Filter {
...
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
chain.doFilter(request, response);
}
...
}
The response wrapper tests the url to be encoded for being a richfaces resource and turns Orchestra's ConversationRequestParameterProvider's separation mode on in the current thread for the time of encoding:
package ...
import javax.faces.application.ResourceHandler;
import org.richfaces.resource.ResourceHandlerImpl;
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider;
public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper {
public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) {
super(httpServletResponse);
}
#Override
public String encodeURL(String url) {
if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) {
boolean current = ConversationRequestParameterProvider.isInSeparationMode();
/* Disable conversationContext parameter in current thread for the time of rendering link to a resource */
ConversationRequestParameterProvider.setInSeparationMode(true);
String result = super.encodeURL(url);
/* Restore */
ConversationRequestParameterProvider.setInSeparationMode(current);
return result;
}
else return super.encodeURL(url);
}
}
(I've had to use String.contains() instead of String.startsWith() when testing the url for being a resource as context path and servlet path happen to prepend the passed url.)
However that does not help either by this moment. The reason is that Orchestra uses its own response wrapping that takes place in its RequestParameterFacesContextFactory, and this wrapping happens after our filter is hit. In this way Orchestra's wrapper turns out to be external to our one which results in our wrapper receiving url too late, when the url has already been intercepted and conversationContext appended.
To avoid this we have a way to make our response wrapper external to Orchestra's one by replacing effect from RequestParameterFacesContextFactory interceptor with RequestParameterServletFilter which actually does the same work. Unfortunately using another filter is not quite exquisite where we might not, but I don't see another way so far.
So, in web.xml place your filter after Orchestra's one:
<filter>
<filter-name>requestParameterFilter</filter-name>
<filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class>
</filter>
<filter>
<filter-name>myOrchestraFilter</filter-name>
<filter-class>mypkg.RfOrchestraParamControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestParameterFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>myOrchestraFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
Could not make previous solutions work. I did it this way:
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;
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.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
/**
* #author Felipe Riccetto
*/
public class RemoveConversationParamFilter implements Filter {
public static String removeQueryParameter(final String url,
final String parameterName) throws URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(url);
List<NameValuePair> queryParameters = uriBuilder.getQueryParams()
.stream().filter(p -> !p.getName().equals(parameterName))
.collect(Collectors.toList());
if (queryParameters.isEmpty()) {
uriBuilder.removeQuery();
} else {
uriBuilder.setParameters(queryParameters);
}
return uriBuilder.build().toString();
}
#Override
public void destroy() {
// nothing
}
#Override
public void doFilter(final ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp2 = new HttpServletResponseWrapper(
(HttpServletResponse) resp) {
#Override
public String encodeURL(String url) {
String s = super.encodeURL(url);
try {
String urlPath = new URL(
((url.toLowerCase().startsWith("http://")
|| url.toLowerCase().startsWith("https://"))
? ""
: "http://fake")
+ url).getPath().toString().toLowerCase();
if (urlPath.endsWith(".js") || urlPath.endsWith(".css")
|| urlPath.endsWith(".png")
|| urlPath.endsWith(".jpeg")
|| urlPath.endsWith(".jpg")
|| urlPath.endsWith(".gif") || urlPath.contains(
ResourceHandler.RESOURCE_IDENTIFIER)) {
s = removeQueryParameter(s, "conversationContext");
}
} catch (MalformedURLException | URISyntaxException e) {
// ignore
}
return s;
}
};
chain.doFilter(req, resp2);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// nothing
}
}
web.xml:
<filter>
<filter-name>RemoveConversationParamFilter</filter-name>
<filter-class>RemoveConversationParamFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RemoveConversationParamFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
This last mapping must be the last in your web.xml
I want to fully internationalize my web page and have URLs translated to different languages. For example
http://example.tld/en/page
http://example.tld/de/pagina
all aforementioned pages should be handled by same controller and show same content (translated to desired language of course, this i know how to do - using message properties).
So my questions are:
How to achieve this functionality using #RequestMapping annotation?
Can I configure such aliases in properties or XML file and then "inject" them into controller? i.e.:
properties file:
alias.page=page:pagina
Controller
#RequestMapping("${alias.page}")
...
Or something like this.
Thanks for answers.
I've solved this issue by creating own implementation of servlet Filter
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class ExampleFilter implements Filter {
#Override
public void init(FilterConfig fc) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain fc) throws IOException, ServletException {
// Needed for getting URL from request
final HttpServletRequest hsRequest = (HttpServletRequest) request;
String url = hsRequest.getRequestURI().substring(
hsRequest.getContextPath().length()
);
/* This is just simple example. Here you can connect to database
or read properties or XML file with your configuration */
if ("/de/pagina".equals(url) || "/en/page".equals(url)) {
// change url and forward
RequestDispatcher dispatcher = request.getRequestDispatcher("/page");
dispatcher.forward(request, response);
} else {
// Do nothing, just send request and response to other filters
fc.doFilter(request, response);
}
}
#Override
public void destroy() {}
}
The controller method to handle request will then look like
#Controller
public class MultiLangController {
#RequestMapping(value="/page", method = RequestMethod.GET)
public String pageMethod() {
return ...;
}
}
Finally publish the new filter into web.xml
<filter>
<filter-name>MyExampleFilter</filter-name>
<filter-class>
com.path.to.filter.ExampleFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>MyExampleFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
And that should do the trick. If you don't need such flexibility, maybe UrlRewriteFilter (analogue of .htaccess for Java) will be sufficient.
Use a PathVariable in the #RequestMapping, with something before it so Spring can map the request:
#RequestMapping("myPage.do")
public String displayBasePage () {
return("pageName"); // a hard-coded JSP
}
becomes
#RequestMapping("/someidentifier/{pageName}.do"
public String displayBasePage (
PathVariable("pageName") String pageName) {
return(pageName); // the language-specific JSP, or whatever else you want to do
}
Spring will match the /someidentifier/ to this RequestMapping, and you can use whatever value you want for the pageName.
Is there any way to make a filtermapping not include subdirectories?
For example.
I have .xhtml files in my context root, and I also have a subfolder named "test" with files with the same extension. Is there any may to map a filter to the files in context root and not to the files in the "test" directory?
The url-pattern is indeed restrictive in matching. It only allows exact, prefix or suffix matchnig. Not midst/overall/regex matching. So e.g. /*.xhtml what you intend to do ain't going to work.
If you want to exclude XHTML in the /test folder only, then your best is really a Filter listening on an url-pattern of *.xhtml which does basically the following job in doFilter() method:
// First cast ServletRequest to HttpServletRequest.
HttpServletRequest hsr = (HttpServletRequest) request;
// Check if requested resource is not in /test folder.
if (!hsr.getServletPath().startsWith("/test/")) {
// Not in /test folder. Do your thing here.
}
The HttpServletRequest#getServletPath() basically returns the part of the request URI from the context path on.
You can if necessary configure the value /test as an <init-param> of the filter so that you can control the value from inside the web.xml instead of in the Filter's code.
The solution, basically you need your own Filter class and define excluding URLs as init-param for filter
package test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginValidationFilter implements Filter {
private String loginPage = "";
private List<String> excludedURLs;
public void init(FilterConfig filterConfig) throws ServletException {
this.loginPage = filterConfig.getInitParameter("loginPage");
String[] excluded = filterConfig.getInitParameter("excludedURLs").split(";");
excludedURLs = new ArrayList<String>();
for (int i = 0; i < excluded.length; i++) {
excludedURLs.add(excluded[i]);
}
}
public void destroy() {
this.loginPage = "";
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
ServletException {
HttpServletRequest httpRequest = request instanceof HttpServletRequest ? (HttpServletRequest) request : null;
HttpServletResponse httpResponse = response instanceof HttpServletResponse ? (HttpServletResponse) response
: null;
if (httpRequest == null || httpResponse == null) {
filterChain.doFilter(request, response);
return;
}
boolean isExcludedURL = false;
for (int i = 0; i < excludedURLs.size(); i++) {
if (httpRequest.getRequestURL().indexOf(excludedURLs.get(i)) > -1) {
isExcludedURL = true;
break;
}
}
if (isExcludedURL) {
filterChain.doFilter(request, response);
} else {
if (UserUtil.validateUserLogin(httpRequest)) {
filterChain.doFilter(request, response);
} else {
httpResponse.sendRedirect(httpRequest.getContextPath() + loginPage);
}
}
}
}
And define the filter, mapping and exclude URLs in web.xml
<filter>
<filter-name>LoginValidationFilter</filter-name>
<filter-class>test.LoginValidationFilter</filter-class>
<init-param>
<param-name>loginPage</param-name>
<param-value>/login.jsp</param-value>
</init-param>
<init-param>
<param-name>excludedURLs</param-name>
<param-value>/admin/;/assets/;/content/;/css/;/js/;/login.jsp;/login.cmd;/logout.cmd;forgot_password.jsp;pageName=</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LoginValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Using what is available for standard servlets/filters, there is no direct way to exclude the subdirectory, since *.ext style mappings include subdirectories. You could work around this by declaring another filter that specifically handles the /test/*.xhtml mapping and handles that accordingly.
You can add a url-mapping value for every file you have in the context root, therefore the filter will apply to those files but none to the files in the test folder (actually it will only apply to those specific files). The following worked for me
<url-pattern>/index.faces</url-pattern>
Some containers (like resin) define an extension to filter mapping definition in web.xml which allows specifying url-regexp which allows matching the urls based on regular expression. (reference). See if your container has something like this.