Note: You’ll find the complete working sources here: Vaadin-SpringSecurityViewProvider.
Finally, the 2nd post in my Vaadin & Spring series. This time about describing, instantiating and managing views with
and through Spring Security.
I’m a big fan of Spring Security as it is – at least for my purposes – incredible easy to add some long standing authorization mechanism we have in our databases. Apart from that, it most of the times just works.
I’ve read a lot about Shiro as well, but instead of learning another framework, i wanted to focus on something i already knew quite well to keep things secure. Regarding security i like to be conservative.
For the basic integration i’m using SpringVaadinIntegration by Alexander Fedorov and i’m very content with it, the ru.xpoft.vaadin.SpringVaadinServlet works very well.
My goals with adding custom stuff to it where the following:
- I want to use Spring Security
- The application need to use a Navigator
- No redundant @Component and @Scope on every view
The following code implies a working Spring + AspectJ, Spring Security and Vaadin setup including the above mentioned SpringVaadinServlet.
So the first thing i came up with is my own ViewDescriptor annotation:
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import com.vaadin.navigator.View; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component @Scope(SCOPE_PROTOTYPE) public @interface ViewDescription { /** The name of the view, also used by the navigator, can be a complete path like /foo/bar/baz */ String name() default ""; /** * @return the Spring-EL expression to be evaluated before the view described here is finally added to the navigator. */ String requiredPermissions() default ""; /** * @return Can this view be cached if caching is available? */ boolean cacheable() default false; } |
This thing can be used on every class implementing “com.vaadin.navigator.View” and makes it a managed spring component.
The next step is naturally to provide those view to the application using a custom ViewProvider. Here’s my solution that maps view names to view classes and retrieves them from the application context. As the components are prototype scoped it will be new instances for every application instance. If the views can and should be cached, this is implemented as well.
My first solution was a custom (overwritten) Navigator in conjunction with a specialized ViewProvider. But after writing this post and creating a custom project i thought a while longer.
In the end it just needs a custom view SpringSecurityViewProvider who takes care of finding views, checking permissions and caching the views if necessary. So in the end i used the stuff from my previous post to create a view provider who has an autowired ApplicationContext and is used in the Applications init method like this:
final ComponentContainerViewDisplay viewDisplay = new ComponentContainerViewDisplay(this.mainContent); this.navigator = new Navigator(UI.getCurrent(), viewDisplay); this.navigator.addProvider( SpringSecurityViewProvider.createViewProvider((Authentication) request.getUserPrincipal()) ); |
The little factory method became necessary because the Application Context cannot be injected into the constructor through it’s transient nature. If i hadn’t the need for the current authentication i probably would have used a @PostConstruct method instead.
In contrast to the first version of this post, the code for the ViewProvider is omitted as i have created a project on Github called Vaadin-SpringSecurityViewProvider. You’ll find the whole source code there including tests that show how to setup a correct load-time-weaving necessary for @Configurable’s.
Using only a custom ViewProvider (which by the way is an interface) is way better than a combination of Navigator and ViewProvider. That way the user can use all navigator constructors and functions.
Our views now looks like this:
@ViewDescription( name=SomeView.VIEW_NAME, requiredPermissions= "isAuthenticated() and " + "@authorizationService.hasExecutionalRight(principal, T(some.enumeration.of.BusinessProcesses).PROCESS_NAME)" ) @DependsOn("application") public class SomeView extends Panel implements View { public final static String VIEW_NAME = "/some/arbitrary/path"; } |
You see all the power of SpEL and Spring Security in the requiredPermissions attribute: Not only checking for authentication but also calling an authorization service with the current principal as parameter and an enum constant describing a business process. The whole thing then actually calls an Oracle stored function by the way.
What do you think about this solution? Any ideas for improvement or comments?
4 comments
Hello Mr Micael,
Im Djamel new in Java2E developement and I need a littel be helped I’m just looking for a littel skeleton of vaadin, spring integration and hibernat to persiste runing under tomcat, just the configuration files. I used Hibernate and Vaadin to build a project and when I start Spring integration I have been lost.
If you have time I can share my code with you;
or if you have a skeleton I will be verry happy.
best regards
Hi Bellal.
What isn’t work? Basic Spring bootstrapping? For that i’d recommend looking at the guides at spring.io.
I’ve no template or skeleton setup at hand, but post your setup and i’ll have a look.
Cheers,
Michael.
Great addon but please i’m newbie to Vaadin world can you provide a simple step by step example of Spring security integration with Vaadin..
Thank you very much
Thanks for your kind feedback!
Post a Comment