I have written an interceptor for my spring-boot app. But when I hit the endpoint, its executing fine.The interceptor is not able to intercept my request.
Where I am going wrong or missing something?
Below is the Code
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
private static final String PATHS = "/services/api/**";
#Autowired
private AuthorizationInterceptor authInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor).addPathPatterns(PATHS);
}
}
Here is the code for Interceptor:::
#Component
public class AuthorizationInterceptor implements HandlerInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationInterceptor.class);
private static final String MSG_BAD_INPUT = "Very Bad Input";
private static final int MAX_URI_LENGTH = 4;
#Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("Inside Prehandle:::::::------->");
this.checkURILength(request);
System.out.println("After checking:::::::::::---->");
return true;
}
private void checkURILength(HttpServletRequest request) {
if (request.getRequestURI().length() > MAX_URI_LENGTH) {
LOGGER.error("Request URI is too long");
throw new InvalidInputException(MSG_BAD_INPUT);
}
}
}
Now when I hit the endpoint for my spring-boot app say, its working fine
http://localhost:8181/services/api/companies
Basically its not at all calling the prehandle.
What am I missing????
Did you used #EnableWebMvc as
#EnableWebMvc
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
}
In my case the use of a MappedInterceptor as described in the answer below worked.
https://stackoverflow.com/a/35948730/1705048
Related
I am trying to create a jar file to inject into any of my spring boot project for logging the request details.
I am able to do this in one of my project. You can see the code below.
How to create the jar out of it and how to inject into other projects?
#Component
public class Interceptor extends HandlerInterceptorAdapter {
private static Logger log = LoggerFactory.getLogger(Interceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// log.info("Inside prehandle");
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// log.info("Inside postHandle");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("Inside afterCompletion");
sendToLoggerApi(request, response);
}
}
#Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
#Autowired
Interceptor interceptor;
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(interceptor);
}
}
I am trying to add junit test case for my Spring Boot OncePerRequestFilter shouldNotFilter method logic. The logic works fine with real-time REST calls but junit case is failing. Any idea?.
Here is test code.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringFilterTest {
#Test
public void getHealthTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/health")).andExpect(status().isOk());
}
#Test
public void getPersonTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/person")).andExpect(status().isAccepted());
}
private class SkipFilter extends OncePerRequestFilter {
private Set<String> skipUrls = new HashSet<>(Arrays.asList("/health"));
private AntPathMatcher pathMatcher = new AntPathMatcher();
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
response.setStatus(HttpStatus.ACCEPTED.value());
}
#Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}
}
#RestController
#RequestMapping(value = "/")
private static class PersonController {
#GetMapping("person")
public void getPerson() {
}
#GetMapping("health")
public void getHealth() {
}
}
}
I am expecting both of junit #Test cases to be successful but health one is always failing(its using Filter).
Incase, if you want to replicate below is complete repo code.
https://github.com/imran9m/spring-filter-test
Below Expression evaluates to false with request.getServletPath() when /health
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
Change to request.getRequestURI() to get the uri and below condition matches the path
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getRequestURI()));
I have several folders in /static/img/** and I need to add interceptors to some of them to check user permissions. I've used interceptors earlier and added them this way:
#SpringBootApplication
#EnableTransactionManagement
public class Application extends WebMvcConfigurerAdapter {
...
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}
#Bean
public AuthHeaderInterceptor authHeaderInterceptor() {
return new AuthHeaderInterceptor();
}
#Bean
public AuthCookieInterceptor authCookieInterceptor() {
return new AuthCookieInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(authHeaderInterceptor())
.addPathPatterns(REST_URL)
.excludePathPatterns(
new String[] {
REST_SECURITY_URL,
REST_SETTINGS_URL,
REST_REPORTS_URL
}
);
registry
.addInterceptor(authCookieInterceptor())
.addPathPatterns(REST_REPORTS_URL);
}
}
All works fine for rest controllers and their URLs, but now I need to secure some static resources and I added this:
#SpringBootApplication
#EnableTransactionManagement
public class Application extends WebMvcConfigurerAdapter {
...
#Bean
public RoleAdminInterceptor roleAdminInterceptor() {
return new RoleAdminInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(authHeaderInterceptor())
.addPathPatterns(REST_URL)
.excludePathPatterns(
new String[] {
REST_SECURITY_URL,
REST_SETTINGS_URL,
REST_REPORTS_URL
}
);
//THIS NOT WORK
registry
.addInterceptor(roleAdminInterceptor())
.addPathPatterns("/static/img/admin/**");
registry
.addInterceptor(authCookieInterceptor())
.addPathPatterns(REST_REPORTS_URL);
}
}
Commented line doesn't work. When I send request to /static/img/admin/test.png RoleAdminInterceptor is never called.
What I'm doing wrong?
I know this is an old question, but since it's unanswered it might help others searching for it.
This is what worked for me:
1- Declare an interceptor class:
class RoleBasedAccessInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
AntPathMatcher matcher = new AntPathMatcher();
String pattern = "/static/img/admin/**";
String requestURI = request.getRequestURI();
if (matcher.match(pattern, requestURI)) {
//Do whatever you need
return validateYourLogic();
}
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2- Configure WebMvcConfigurer
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RoleBasedAccessInterceptor());
}
}
I think in this case you could use Filters with Spring Security instead of Interceptors as you could Validate the access earlier on the process even before hitting the Interceptor, unless there is a specific use case that you need to use the interceptor here.
Some topic about the difference between these two:
filters-vs-interceptor
This is my controller class:
#Component
#RequestMapping("/test")
public class MyController
{
#RequestMapping(value = {"test"}, method = RequestMethod.GET)
#ResponseBody
public String test(#MyAnnotation String myValue)
{
return "myValue:"+myValue;
}
}
Moreover, below is my interceptor class:
public class MyInterceptor implements HandlerInterceptor
{
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
MyAnnotation annotation = ((HandlerMethod)handler).getMethod().getAnnotation(MyAnnotation.class);
// TODO
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception
{
}
}
if I want myValue to be "test", then how to implement the custom annotation #MyAnnotation? what to do in class MyInterceptor
I am using Guice with JDO and Datanucleus in my desktop app. I am facing a NPE that I can't fix, so I hope someone can help me :)
I am using properly configured H2 db, with schema created and all my classes are nicely enhanced, so it's not that. Anyway, I am getting NPE here, at JDORepository class:
public abstract class JdoRepository<T> implements Repository<T>
{
private final Class<T> clazz;
private final Provider<PersistenceManager> pmProvider;
protected JdoRepository(Class<T> clazz, Provider<PersistenceManager> pmProvider)
{
this.clazz = clazz;
this.pmProvider = pmProvider;
}
public void persist(T entity)
{
pmProvider.get().makePersistent(entity); <---- NPE!
}
My PersistenceManagerFilter looks like that:
#Singleton
public class PersistenceManagerFilter implements Filter
{
private static final Logger logger = Logger.getLogger(PersistenceManagerFilter.class.getName());
private static final ThreadLocal<PersistenceManager> pm = new ThreadLocal<PersistenceManager>();
private PersistenceManagerFactory pmf;
public void init(FilterConfig filterConfig) throws ServletException
{
logger.info("Creating PersistenceManagerFactory");
pmf = JDOHelper.getPersistenceManagerFactory();
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
try
{
pm.set(pmf.getPersistenceManager());
chain.doFilter(request, response);
}
finally
{
pm.get().close();
}
}
public void destroy()
{
logger.info("Closing PersistenceManagerFactory");
pmf.close();
}
/**
* This module binds the JDO {#link javax.jdo.PersistenceManager} interface to the provider that allows the
* implementation to be injected as Provider<PersistenceManager>.
*/
public static class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
bind(PersistenceManager.class).toProvider(new Provider<PersistenceManager>()
{
public PersistenceManager get()
{
return PersistenceManagerFilter.pm.get();
}
});
}
}
}
And the responsible module:
public class GuiceModule extends AbstractModule
{
#Override
protected void configure()
{
// Enable per-request-thread PersistenceManager injection.
install(new PersistenceManagerFilter.GuiceModule());
bind(new TypeLiteral<Repository<Project>>() { }).to(JdoProjectRepository.class);
I am initiating it all that way:
Injector injector = Guice.createInjector(new GuiceModule());
Main main = injector.getInstance(Main.class);
main.run();
So repository bindings in main class work fine, as they are redirected to JDORepository. It's something at lower level, PMF not getting bound properly? Any ideas?
What does your main.run()-method do? Does it call PersistenceManagerFilter#doFilter? If it doesn't, the value in yourThreadLocal<PersistenceManager> will be null...
You could override the initialValue() and do something like this:
ThreadLocal<PersistenceManager> pm = new ThreadLocal<PersistenceManager>(){
#Override
protected PersistenceManager initialValue() {
return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
}
};
You should also remember to call the ThreadLocal#remove() method in your finally-block.
Instead of handling the ThreadLocal yourself, you could bind the PersistenceManager directly in the guice-module:
class GuiceModule extends AbstractModule {
#Provides #RequestScoped
PersistenceManager providePersistenceManager(){
return JDOHelper.getPersistenceManagerFactory().getPersistenceManager();
}
#Override
protected void configure() {}
}