intercept spring mvc controller call based on annotations - java

I have the following controller in spring MVC
#GetMapping("/id/kw")
public ModelAndView industryWater(HttpServletRequest request) {
return someMAV
}
I want to cut into the execution of the controller based on customized annotation
#GetMapping("/id/kw")
#WaterBefore
#WaterAfter
public ModelAndView industryWater(HttpServletRequest request) {
return someMAV
}
I can probably inject some thing using BEAN postProcessor, but I don't know how to hook my injected part with the controller execution. Also I need to access the context request mav when implementing my water aspect.
I researched a bit BeanPostProcessor, Interceptor, but didn't manage to connect all pieces.

I think you need to use AOP in Spring. that is very useful. it`s using transaction management and using logging etc.
Spring AOP (Aspect-oriented programming) framework is used to modularize cross-cutting concerns in aspects. If you want a more simple definition you can think of them as a Interceptor but with more options configurations possible. In Spring there are two different constructs that get called “interceptors”. First, there are Handler Interceptors, which are part of the Spring MVC framework and give you the ability to add interceptor logic to requests. But you also have Method Interceptors, which are part of the Spring AOP framework. These are much more general mechanism than Handler Interceptors, but also potentially more complex. In AOP terminology, such interceptors provide a means of coding the “aspects” you’re talking about.
Like this :
#Pointcut(" execution (* com.your.controller.industryWater(..))")
public void pointcutDemo() {}
#Before("pointcutDemo())")
public void logBefore(){ }
#After("pointcutDemo())")
public void logAfter(){ }
link : https://www.mkyong.com/spring3/spring-aop-aspectj-annotation-example/
https://www.journaldev.com/2583/spring-aop-example-tutorial-aspect-advice-pointcut-joinpoint-annotations
http://www.baeldung.com/spring-mvc-handlerinterceptor

Related

Spring MVC Controller as Liferay Portlet and Servlet

We are trying to have a spring MVC Controller that works as a portlet and a servlet, in order to be deployed in a Liferay context or as a standalone version. But it seems that the we have a conflict if we decide to have multiple RequestMappings on the method level (as opposed to having just 1 mapping on the level of the controller). we get the error shown below.
Note that if we decide to just have a requestMapping on the level of the controller that hosts a servlet mapping and a portlet mapping, it works.
#RequestMapping({"view", "/"})
The controller that does not work:
#Controller("controller")
#RequestMapping("VIEW")
public class MyController {
#RenderMapping
public ModelAndView doView(RenderRequest request, RenderResponse response) throws Exception {
HttpServletRequest portletHttpReq = PortalUtil.getHttpServletRequest(request);
HttpServletResponse portletHttpResp = PortalUtil.getHttpServletResponse(response);
return doView(portletHttpReq, portletHttpResp);
}
#RequestMapping(value="/home")
protected ModelAndView doView(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
// do something
return new ModelAndView("view");
}
}
The resulting error:
[...]
Caused by: java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/home] versus [view]
Do you have any suggestions on how we could implement such thing? What we would really like to avoid is having to maintain 2 controllers for every portlet/servlet.
Thank you.
I don't really think this is a good idea... the #RequestMapping annotation on the class level is going to cause problems for sure, simply because Spring portlet MVC expects the portlet mode, while Spring Web MVC expects a root URL.
Also, your code doesn't seem to be correct either, since ModelAndView exists in both the portlet MVC as the web MVC part of the Spring framework, and since you cannot import both, you'll have to specify the full package for one of them, and since you're not doing that either, your code is just wrong.
Except the technical issues, both portlets and servlet have different terminology and point of views. These are some key questions that pop up with me if I hear this:
What are you going to do about the different phases (ACTION and RENDER)
What about the the different portlet modes (VIEW, EDIT, HELP, ...)
What are you going to do about the specific portlet features (PortletSession, PortletPreferences, ...)
How are you going to handle the different kind of requests (ResourceRequest, ActionRequest, RenderRequest, PortletRequst, EventRequest vs HttpServletRequest)
How are you going to handle security? The portal container provides authentication for you, a standalone web application does not.
And these are just questions from a portlet mindset, I'm pretty sure there are also technical issues if you look at it from the web application point of view.
It makes much more sense to divide your code into a view layer and business logic. Put the business logic in a separate package or separate services, and build a separate portlet- and standalone application, using the same/shared business logic.

security util using SecurityContextHolder in spring application

in my spring application I have some aspects for controller methods where I do some security checks. beacause of I need several checks more often I wrapped them into static helper methods of a "sercurityUtil" class.:
public abstract class SecurityUtils {
public static Authentication getCurrentAuthentication(){
return SecurityContextHolder.getContext().getAuthentication();
}
public static ChroniosUser getAuthenticatedUser(){
return (ChroniosUser) getCurrentAuthentication().getPrincipal();
}
public static boolean authenticationHasRole(Authentication authentication, Role role){
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRoleIdentifier());
return authentication.getAuthorities().contains(grantedAuthority);
}
public static boolean authenticatedUserIsAdmin(){
Authentication authentication = getCurrentAuthentication();
return authenticationHasRole(authentication, ADMIN);
}
...
}
is this a valid and good approach?
or shut I wrap these helper functions into a spring service?
thank you.
PS: I know that I can use #PreAuthorize ... but my aspects are more complex.
The short answer is :
Yes it seems to be a valid and good approach.
The long answer is :
It's up to you.
Spring Security documentation states that its infrastructure is based entirely on standard servlet filters and has no strong links to any particuler web technology, including Spring MVC
Spring Security’s web infrastructure is based entirely on standard
servlet filters. It doesn’t use servlets or any other servlet-based
frameworks (such as Spring MVC) internally, so it has no strong links
to any particular web technology. It deals in HttpServletRequest s and
HttpServletResponse s and doesn’t care whether the requests come from
a browser, a web service client, an HttpInvoker or an AJAX application
[Spring Security Reference - 1. The Security Filter Chain]
Its use is based nearly entirely on the SecurityContextHolder. The examples provided are through static methods :
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
As you can see, it's not a Spring Bean/Service/Component. SecurityContextHolder itself looks like a utility class.
Now you can create a Spring Service to expose it or you can use it through a classic Util class depending on what is more practical to you and for your application.

Good way to handle sessions in Spring MVC

I was wondering if there is a better way to handle handling sessions than running this set of code through each one of my controller methods.
public ModelAndView addUser(#RequestParam("userid") String userId,
#RequestParam("passwd") String passwd,
#RequestParam("usrtype") String usrtype,
HttpSession session,
Model model ){
ModelAndView mav = new ModelAndView();
if ((String) session.getAttribute("userId") == null) {
model.addAttribute("msg", "Session was terminated.");
model.addAttribute("url", "/login");
mav.setViewName("redirect");
return mav;
}
...
How would one go about making this into reusable code?
There are multiple ways to optimize this:
Securing requests is something Spring Security is made for. Spring Security uses a Servlet filter to intercept (and deny) requests before they arrive in your controller. So you do not have to handle security related code in controller actions
If, for whatever reason, you can/want not use Spring Security you should have a look at Spring's MVC interceptions. In interceptors you can place code that need to be executed before and after controller actions.
If you always need to set the same Model attribute you can annotate methods with #ModelAttribute. This method will then be called for every request to populate your model, see ModelAttribute methods documentation. ControllerAdvice is similar, it is used if other classes than the controller should provide model information.

Does Spring generate code for validaiton?

lately I was trying to understand how spring processes #Valid annotation. For example look at the following controller's method:
#RequestMapping(value = "/create", method = RequestMethod.POST)
public ModelAndView createEmployee(#Valid EmployeeForm form, Errors errors) {
if(errors.hasErrors()) {
//validation errors
}
//method code
}
I am struggling to understand how errors instance is getting populated with validation errors in real-time. Does Spring, during compilation of the controller, inject code responsible for validation at the beginning of the createEmployee method? If so how this code would look?
I really tried to find an example of how this validation is performed in real life but it's just impossible. Help me please.
Everything happens at runtime. See the reference for more details on doing validation or this post for extra explanations.
Basically this is part of how Spring works internally. When you start your application Spring registers some beans, bean processors, can scan your classpath for annotated classes, registers those found annotated classes, builds proxies for some of them etc and uses all of them to build a context.
When handling a request, the request is handled on some predetermined execution path that starts with the DispatcherServlet, picking up other beans from the context as needed to handle the request (like validation for example) then forwarding to you controller in the createEmployee (which was registered as startup because Spring found your #RequestMapping annotations on your controller). When you return from the method the flow continues by building a model, selecting a view to display and then generating the response to the client.
For your example, Spring basically finds the #Valid annotation, looks for an already configured validator (configured by you or by a provided implementation for e.g. JSR-303), runs the validator and stores the validation result inside the Errors object. It does this when the request is processed, as mentioned above, it does not generate code.
If your question is to know exactly how Spring does this, in all it's details, you could take the Spring source code and have a look/debug it.

Securing Methods with Spring Security

For our current project, we are integrating JSF and the Spring Framework. I'd like to use Spring Security to handle authentication and authorization. So far, I have implemented a custom PasswordEncoder and AccessDecisionVoter which are working fine. Now I'm trying to secure methods using the #Secured annotation (among others) but I can't get that to work as I would expect it to do.
It seems that the #Secured annotation works for bean methods called directly from the JSF layer, only. Here's a simplified example:
#Named("foobarBean")
#Scope("access")
public class FoobarBean
{
#Secured("PERMISSION_TWO")
public void dummy()
{
}
#Secured("PERMISSION_ONE")
public String save()
{
dummy();
}
}
The method save() is called from the JSF layer like this:
<h:commandButton id="save" action="#{foobarBean.save}" />
Our AccessDecisionVoter is then asked to vote on PERMISSION_ONE but not on PERMISSION_TWO. Is this working as designed (I hope not) or am I doing something wrong (what could that be?).
I'd post more code or config but I'm not sure which part is relevant, and I don't want to clutter this post.
It is a simple problem of Proxy AOP! If you use Proxy AOP for Security, then the Proxy can only intercept calles that go through the proxy. If one method invoke an other method of the same bean directly, then there is no proxy that can intercept this call. -- And this is the reason why only the the Security Annotation of save() is taken in account.
One solution would be using AspectJ AOP instead of Proxy AOP. (It is supported by Spring (Security) too.)
Yes, That is how the AccessDecisionVoter works. It takes all roles allowed on a resource(method in your case) and vote for those roles form the current authenticated user's role. If the Role is matched, then only the permission is granted.
In your case also, the only Role defined for the save method is PERMISSION_ONE so the security system will check against this role only. If logged in user has that role, this method will be executed.

Categories