Imagine I have defined these REST endpoints:
@RequestMapping(path = "/user")
@RestController
public class ConfigUserController {
[...]
@GetMapping(path = "/variables/")
public ResponseEntity<List<Variable>> getAllVariables(...)
[...]
}
@GetMapping(path = "/variables/{name}")
public ResponseEntity<Variable> getVariableByName(...)
[...]
}
@PutMapping(path = "/variables/{name}/{value}")
public ResponseEntity<Variable> setVariableByName(...)
[...]
}
}
I've defined two filter (logging and authorization), inside the filters I want to get the url-patter which matched current request. Using the example above:
- if the request was a GET to /variables, I want "/variables"
- if the request was a GET to /variables/myfancyname, I want "/variables/{name}"
- if the request was a PUT to /variables/myfancyname/myvalue, I want "/variables/{name}/{value}"
Basically what I need is to get the path defined in the mapping annotation inside the doFilter(ServletRequest request, ServletResponse response, FilterChain chain) method of my filters.
Ideally I want to have do the possibility to access the url-pattern value in my filter like this:
@Component
@Order(3)
public class MyAuthorizationRequestFilter extends GenericFilterBean {
[...]
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// here I get the value
String urlPattern = request.useSomeMethod().toGetUrlPattern();
[...]
boolean auth = false;
// here I do stuff
[...]
// finally let's see if the user is authorized
if (auth) {
chain.doFilter(request, responde);
} else {
throw SomeAuthorizationError();
}
}
[...]
}
I've been searching but I wasn't able to find a working solution.
If it's possible I prefer not to scan for collections or web.xml files (which I don't have), nor using reflections, because the code will be executed every time the filter get triggered and I don't want to affect performance.
Links or suggestions are welcome.
EDIT: added details, addes filter example cose
CodePudding user response:
Assuming that you are using spring web here.
You can define an HandlerInterceptor
and register it with InterceptorRegistry
.
@Component
public class LogPathTemplateInterceptor
implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
String pathTemplate = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println("Incoming Request path Template : " pathTemplate);
return true;
}
}
After defining this, register it with InterceptorRegistry. See how the path pattern added to the interceptor.
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private LogPathTemplateInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor)
.addPathPatterns("/variables/**");
}
}
This should log the request template path instead of path with variables.
CodePudding user response:
Here is a solution using Servlet filter
Your Controller
@RequestMapping(path = "/user")
@RestController
public class ConfigUserController {
@GetMapping(path = "/variables/")
public ResponseEntity<List<Variable>> getAllVariables() {
return null;
}
@GetMapping(path = "/variables/{name}")
public ResponseEntity<Variable> getVariableByName(@PathVariable("name") String name) {
return new ResponseEntity<Variable>(new Variable(name), HttpStatus.OK);
}
@PutMapping(path = "/variables/{name}/{value}")
public ResponseEntity<Variable> setVariableByName() {
return null;
}
}
Custom Filter
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerMapping;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
System.out.println("Request template is, " pattern);
}
O/P:
Request template is, /user/variables/{name}
Note* Do the chain.doFilter first before trying to do the call to getAttribute
More Information -
https://boudhayan-dev.medium.com/demystifying-spring-security-setup-e0491acc7df7
https://www.javadevjournal.com/spring-security/spring-security-filters/
https://www.javadevjournal.com/spring-security/custom-filter-in-spring-security/