Vaadin Spring Security Example
1. Introduction
Vaadin is a web application framework written in Java, and is built on Google Web Toolkit from Vaadin Ltd.
Spring Security is a part of Spring framework that focuses on providing both authentication and authorization to Java applications. Both Vaadin and Spring Security are open sourced and licensed under the Apache 2.0 license.
In this example, we will build a web application in three steps:
- Create a Vaadin web application from the Vaadin archetype
- Modify the generated Vaadin web application with model-view-controller patterns
- Secure the Vaadin web application with a login page via Spring Security framework
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101 (1.8.x will do fine)
- Maven 3.3.9 (3.3.x will do fine)
- Eclipse Mars (Any Java IDE would work)
- Vaadin 8.1.5 (7.x will do fine)
- Spring Security 4.2.3.RELEASE (5.x will do fine)
- Jetty 9.x
3. A Generated Vaadin Web Application
Vaadin is designed for creating rich and interactive applications that run in the browser. If you have not worked with Vaadin before, please check it out here.
In this step, we will create a web application via the Vaadin Maven archetype.
3.1 Create a Vaadin Maven Project
Install the Eclipse Vaadin plug-in by following the instructions here.
Create a Vaadin Maven project with the steps below:
- File->New->Vaadin->Vaadin 8 Project, then click next
- Keep the default option as
Single-Module Application Project
, then click next - Enter the Group Id as
jcg.demo
and Artifact Id asVaadin-Spring-Security
, then hit finish
It will generate a Maven Vaadin project with MyUI.java
and README.txt
. Follow the instructions in README.txt
to build and run the project.
3.2 Review Generated MyUI.java
The generated MyUI.java
has an init
method which constructs a VerticalLayout
with a TextField
to take the user’s input and a Click Me
button. The Click Me
button displays the entered data.
MyUI.java
package jcg.demo.ui.vaadin; import javax.servlet.annotation.WebServlet; import com.vaadin.annotations.Theme; import com.vaadin.annotations.VaadinServletConfiguration; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinServlet; import com.vaadin.ui.Button; import com.vaadin.ui.Label; import com.vaadin.ui.TextField; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; /** * This UI is the application entry point. A UI may either represent a browser window * (or tab) or some part of a html page where a Vaadin application is embedded. * <p> * The UI is initialized using {@link #init(VaadinRequest)}. This method is intended to be * overridden to add component to the user interface and initialize non-component functionality. */ @Theme("mytheme") public class MyUI extends UI { @Override protected void init(VaadinRequest vaadinRequest) { final VerticalLayout layout = new VerticalLayout(); final TextField name = new TextField(); name.setCaption("Type your name here:"); Button button = new Button("Click Me"); button.addClickListener( e -> { layout.addComponent(new Label("Thanks " + name.getValue() + ", it works!")); }); layout.addComponents(name, button); layout.setMargin(true); layout.setSpacing(true); setContent(layout); } @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) public static class MyUIServlet extends VaadinServlet { } }
3.3 Demo Generated Vaadin Web Application
Execute Jetty:run
and go to http://localhost:8080
. Enter a name and then hit the Click Me
button. Repeat this process with different names and see the different outcomes.
Note: The entered data is displayed on top of each other.
4. Modify the Vaadin Application
Model View Controller (MVC) is a very useful and popular design pattern for a web application.
In this step, we will modify the generated MyUI.java
by displaying the view data from a data model class: InputData
and using the controller class InputController
to set the view data.
4.1 Data Model
Create an InputData
model to capture the name
from the user’s input and moreData
from the back end service’s operation. It is the “Model” part of MVC.
InputData.java
package jcg.demo.model; public class InputData { public InputData() { super(); } public InputData(String name) { super(); this.name = name; } private String name; private String moreData; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMoreData() { return moreData; } public void setMoreData(String moreData) { this.moreData = moreData; } }
4.2 Service
Create an UserDataService
to look up the additional data based on the name
. It will be used by the controller.
UserDataService.java
package jcg.demo.service; import org.springframework.stereotype.Service; import jcg.demo.model.InputData; @Service public class UserDataService { public InputData findData(String name) { InputData inputData = new InputData(name); switch (name) { case "mary": inputData.setMoreData("Zheng"); break; case "tom": inputData.setMoreData("Johnson"); break; default: inputData.setMoreData("Cool dude!"); } return inputData; } }
4.3 Controller
Create an InputController
to return the InputData
created at step 4.1 based on the user’s input. This is the “Controller” part of the MVC.
InputController.java
package jcg.demo.ui.vaadin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import jcg.demo.model.InputData; import jcg.demo.service.UserDataService; @Component public class InputController { @Autowired private UserDataService userService ; public InputData setUserInput(String value) { return userService.findData(value); } }
4.4 View
Modify the generated MyUI.java
to display the data from InputData
created at step 4.1 which is set by the InputController
created at step 4.3. This is the “View” part of MVC.
MyUI.java
package jcg.demo.ui.vaadin; import javax.servlet.annotation.WebServlet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import com.vaadin.annotations.Theme; import com.vaadin.annotations.VaadinServletConfiguration; import com.vaadin.server.Page; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinService; import com.vaadin.spring.annotation.SpringUI; import com.vaadin.spring.server.SpringVaadinServlet; import com.vaadin.ui.Button; import com.vaadin.ui.Label; import com.vaadin.ui.TextField; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import jcg.demo.model.InputData; /** * This UI is the application entry point. A UI may either represent a browser * window (or tab) or some part of an HTML page where a Vaadin application is * embedded. * * The UI is initialized using {@link #init(VaadinRequest)}. This method is * intended to be overridden to add component to the user interface and * initialize non-component functionality. */ @SuppressWarnings("serial") @Theme("mytheme") @SpringUI(path = "/app") public class MyUI extends UI { @Autowired private InputController controller; private InputData inputData; @Override protected void init(VaadinRequest vaadinRequest) { final VerticalLayout layout = new VerticalLayout(); final TextField name = new TextField(); name.setCaption("Type your name here:"); Label sessionIdLabel = new Label(); Label dataFromService_Name = new Label(); dataFromService_Name.setVisible(false); Label dataFromService_more = new Label(); dataFromService_more.setVisible(false); layout.addComponent(name); layout.addComponent(sessionIdLabel); layout.addComponent(dataFromService_Name); layout.addComponent(dataFromService_more); Button button = new Button("Click Me"); button.addClickListener(e -> { inputData = controller.setUserInput(name.getValue()); String sessionID = ((com.vaadin.server.VaadinServletRequest) VaadinService.getCurrentRequest()) .getHttpServletRequest().getSession().getId(); sessionIdLabel.setValue(sessionID); dataFromService_Name.setValue("Thanks, you entered: " + inputData.getName() ); dataFromService_Name.setVisible(true); dataFromService_more.setValue("Thanks, it has more data: " + inputData.getMoreData() ); dataFromService_more.setVisible(true); }); layout.addComponent(button); setContent(layout); } @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) public static class MyUIServlet extends SpringVaadinServlet { } }
4.5 Demo Modified Vaadin Web Application
Execute Jetty:run
and go to http://localhost:8080
.
Enter a name and then click the Click Me
button several times.
Note: Only the last entered data is displayed.
5. Secure the Web Application
If you already know how to use Spring Security, skip forward, if not, check it out here.
Spring Security framework has two key context objects which an application must interact with:
SecurityContextHolder
–SecurityContextHolder
contains information about the current security context of the application, which includes detailed information about the user currently working with the application.UserDetailsService
–UserDetailsService
is used to create aUserDetails
object by implementing the single method of this interface:UserDetails loadUserByUsername (String username) throws UsernameNotFoundException
There are four steps needed to secure a web application with a login page via the Spring Security framework:
- The user logs in with a name and a password. These two credentials are combined into an instance of the class
UsernamePasswordAuthenticationToken
. Then, they are passed to theAuthenticationManager
for verification. - If the username does not match the password, the
BadCredentialsException
is returned along with the message “Bad Credentials.” - If the username and password match, it will return a populated
authentication
instance. - The user sets a security context by calling the
SecurityContextHolder.getContext().setAuthentication()
method, where the object that returned fromauthenticationProvider.authenticate()
is passed.
5.1 Dependencies
Modify the POM.xml to add the Spring Security framework dependencies.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.demo.mary</groupId> <artifactId>vaadin-spring-security</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>Vaadin Spring Security Integration</name> <prerequisites> <maven>3</maven> </prerequisites> <properties> <spring.version>4.2.3.RELEASE</spring.version> <vaadin.version>8.1.5</vaadin.version> <vaadin.plugin.version>8.1.5</vaadin.plugin.version> <jetty.plugin.version>9.3.9.v20160517</jetty.plugin.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <vaadin.widgetset.mode>local</vaadin.widgetset.mode> </properties> <repositories> <repository> <id>vaadin-addons</id> <url>http://maven.vaadin.com/vaadin-addons</url> </repository> </repositories> <dependencyManagement> <dependencies> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-bom</artifactId> <version>${vaadin.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-server</artifactId> </dependency> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-push</artifactId> </dependency> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-client-compiled</artifactId> </dependency> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-themes</artifactId> </dependency> <dependency> <groupId>com.vaadin</groupId> <artifactId>vaadin-spring</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.0.0</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> <!-- Exclude an unnecessary file generated by the GWT compiler. --> <packagingExcludes>WEB-INF/classes/VAADIN/widgetsets/WEB-INF/**</packagingExcludes> </configuration> </plugin> <plugin> <groupId>com.vaadin</groupId> <artifactId>vaadin-maven-plugin</artifactId> <version>${vaadin.plugin.version}</version> <executions> <execution> <goals> <goal>update-theme</goal> <goal>update-widgetset</goal> <goal>compile</goal> <!-- Comment out compile-theme goal to use on-the-fly theme compilation --> <goal>compile-theme</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-clean-plugin</artifactId> <version>3.0.0</version> <!-- Clean up also any pre-compiled themes --> <configuration> <filesets> <fileset> <directory>src/main/webapp/VAADIN/themes</directory> <includes> <include>**/styles.css</include> <include>**/styles.scss.cache</include> </includes> </fileset> </filesets> </configuration> </plugin> <!-- The Jetty plugin allows us to easily test the development build by running jetty:run on the command line. --> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>${jetty.plugin.version}</version> <configuration> <scanIntervalSeconds>2</scanIntervalSeconds> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <version>1.0-beta-1</version> </plugin> </plugins> </build> <profiles> <profile> <!-- Vaadin pre-release repositories --> <id>vaadin-prerelease</id> <activation> <activeByDefault>false</activeByDefault> </activation> <repositories> <repository> <id>vaadin-prereleases</id> <url>http://maven.vaadin.com/vaadin-prereleases</url> </repository> <repository> <id>vaadin-snapshots</id> <url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>vaadin-prereleases</id> <url>http://maven.vaadin.com/vaadin-prereleases</url> </pluginRepository> <pluginRepository> <id>vaadin-snapshots</id> <url>https://oss.sonatype.org/content/repositories/vaadin-snapshots/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </pluginRepository> </pluginRepositories> </profile> </profiles> </project>
5.2 UserDetailsService Interface
Spring Security framework provides UserDetailsService
interface which allows an application to implement the loadUserByUsername
method. Create AuthUserDetailsService
by implementing UserDetailsService's
loadUserByUsername
.
AuthUserDetailsService.java
package jcg.demo.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class AuthUserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService { @Autowired private AuthUserLookUpService userLookupService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userLookupService.findUser(username); } }
5.3 Service
Create an AuthUserLookUpService
to set up two users for the web application.
AuthUserLookUpService.java
package jcg.demo.service; import org.springframework.stereotype.Service; import jcg.demo.model.User; @Service public class AuthUserLookUpService { User findUser(String username) { User found = null; switch (username) { case "admin": found = new User("admin", "admin"); break; case "mzheng": found = new User("mzheng", "great"); break; } return found; } }
5.4 Login Page
Create a LoginUI
which allows users to enter their username and password and authenticate it before continuing onto the main application. The AuthenticationProvider
is utilized to authenticate the user, and if the user passes the authentication, then they are directed to the main application page, otherwise display the error message.
LoginUI.java
package jcg.demo.ui.vaadin; import java.net.MalformedURLException; import java.net.URI; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import com.vaadin.annotations.Theme; import com.vaadin.server.Page; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServletRequest; import com.vaadin.server.VaadinServletResponse; import com.vaadin.spring.annotation.SpringUI; import com.vaadin.ui.Alignment; import com.vaadin.ui.LoginForm; import com.vaadin.ui.Notification; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; /** * This is the form login page. * * */ @SuppressWarnings("serial") @Theme("mytheme") @SpringUI(path = "/login") public class LoginUI extends UI { @Autowired private AuthenticationProvider authenticationProvider; @Autowired SessionAuthenticationStrategy sessionAuthenticationStrategy; @Override protected void init(final VaadinRequest request) { if (!(SecurityContextHolder.getContext().getAuthentication() instanceof AnonymousAuthenticationToken)) { URI currentLoc = Page.getCurrent().getLocation(); try { Page.getCurrent().setLocation( currentLoc.toURL().toString().replace("/login", "/app")); } catch (MalformedURLException e1) { e1.printStackTrace(); } return; } VerticalLayout vl = new VerticalLayout(); LoginForm lf = new LoginForm(); lf.addLoginListener(e -> { final Authentication auth = new UsernamePasswordAuthenticationToken(e.getLoginParameter("username"), e.getLoginParameter("password")); try { // this is the code for achieving the spring security authentication in a programmatic way final Authentication authenticated = authenticationProvider.authenticate(auth); SecurityContextHolder.getContext().setAuthentication(authenticated); sessionAuthenticationStrategy.onAuthentication(auth, ((VaadinServletRequest)VaadinService.getCurrentRequest()).getHttpServletRequest(), ((VaadinServletResponse)VaadinService.getCurrentResponse()).getHttpServletResponse()); URI currentLoc = Page.getCurrent().getLocation(); try { Page.getCurrent().setLocation( currentLoc.toURL().toString().replace("/login", "/app")); } catch (MalformedURLException e1) { e1.printStackTrace(); } } catch (final AuthenticationException ex) { String message = "Incorrect user or password:" + ex.getMessage() + e.getLoginParameter("username") + ":" + e.getLoginParameter("password"); Notification.show(message, Notification.Type.ERROR_MESSAGE); } }); vl.addComponent(lf); vl.setComponentAlignment(lf, Alignment.MIDDLE_CENTER); vl.setSizeFull(); setContent(vl); } }
- line 61: create
UsernamePasswordAuthenticationToken
from the login form - line 64: invoke
authenticationProvider.authenticate
for the username and password - line 65: set
SecurityContextHolder.getContext().setAuthentication
5.5 Security Configuration
Spring Security framework provides WebSecurityConfigurerAdapter
to allow an application to configure the security.
In this step, we will create a SecurityConfig
class by extending it from WebSecurityConfigurerAdapter
, and overriding the configure
method to specify the LoginUI
as the loginPage
.
SecurityConfig.java
package jcg.demo.spring; import java.util.LinkedList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy; import com.vaadin.spring.annotation.EnableVaadin; /** * This class is the main security configuration class. For more information of * how to configure the security, go to * https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html * * */ @EnableWebSecurity @Configuration @ComponentScan(basePackages = { "jcg.demo" }) @EnableVaadin public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(final AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); } @Bean public DaoAuthenticationProvider authenticationProvider() { final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(encoder()); return authProvider; } @Override protected void configure(final HttpSecurity http) throws Exception { http .csrf().disable() .authorizeRequests() .antMatchers("/VAADIN/**", "/HEARTBEAT/**", "/UIDL/**", "/resources/**", "/login", "/login**", "/login/**").permitAll() .anyRequest().authenticated() .antMatchers("/app").access("hasAuthority('USE-APP-ROLE')").and() .formLogin().loginPage("/login?auth").permitAll().defaultSuccessUrl("/app", true).and() .sessionManagement().sessionAuthenticationStrategy(sessionControlAuthenticationStrategy()); } @Bean public SessionAuthenticationStrategy sessionControlAuthenticationStrategy(){ SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy(); sessionFixationProtectionStrategy.setMigrateSessionAttributes(false); RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy = new RegisterSessionAuthenticationStrategy(sessionRegistry()); List strategies = new LinkedList(); strategies.add(sessionFixationProtectionStrategy); strategies.add(registerSessionAuthenticationStrategy); CompositeSessionAuthenticationStrategy compositeSessionAuthenticationStrategy = new CompositeSessionAuthenticationStrategy(strategies); return compositeSessionAuthenticationStrategy; } @Bean public SessionRegistry sessionRegistry() { SessionRegistry sessionRegistry = new SessionRegistryImpl(); return sessionRegistry; } public PasswordEncoder encoder() { return NoOpPasswordEncoder.getInstance(); } }
- line 42: Auto wire
UserDetailsService
created at step 5.2 - line 52: Use the
UserDetailsService
created at line 42 in theauthProvider
- line 58-66: Configure the
HttpSecurity
5.6 Initialize Security Web Application
Spring Security framework provides AbstractSecurityWebApplicationInitializer
to allow a web application to initialize the Spring Security context. In this step, we will initialize the Spring Security context with the SecurityConfig
created at Step 5.3.
SecurityWebApplicationInitializer.java
package jcg.demo.spring; import javax.servlet.ServletContext; import javax.servlet.annotation.WebListener; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; import org.springframework.security.web.session.HttpSessionEventPublisher; /** * This class will initialize the spring security framework * */ @WebListener public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { public SecurityWebApplicationInitializer() { super(SecurityConfig.class); } @Override protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { super.beforeSpringSecurityFilterChain(servletContext); servletContext.addListener(new HttpSessionEventPublisher()); } }
- line 17: set
SecurityConfig
at theSecurityWebApplicationInitializer
5.7 Modify View to Add a Logout Button
Modify MyUI.java to add a logout button, which will invalidate the current session, and redirect the page to the root of the application.
MyUI .java
package jcg.demo.ui.vaadin; import javax.servlet.annotation.WebServlet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import com.vaadin.annotations.Theme; import com.vaadin.annotations.VaadinServletConfiguration; import com.vaadin.server.Page; import com.vaadin.server.VaadinRequest; import com.vaadin.server.VaadinService; import com.vaadin.spring.annotation.SpringUI; import com.vaadin.spring.server.SpringVaadinServlet; import com.vaadin.ui.Button; import com.vaadin.ui.Label; import com.vaadin.ui.TextField; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import jcg.demo.model.InputData; /** * This UI is the application entry point. A UI may either represent a browser * window (or tab) or some part of an HTML page where a Vaadin application is * embedded. * * The UI is initialized using {@link #init(VaadinRequest)}. This method is * intended to be overridden to add component to the user interface and * initialize non-component functionality. */ @SuppressWarnings("serial") @Theme("mytheme") @SpringUI(path = "/app") public class MyUI extends UI { @Autowired private InputController controller; private InputData inputData; @Override protected void init(VaadinRequest vaadinRequest) { final VerticalLayout layout = new VerticalLayout(); final TextField name = new TextField(); name.setCaption("Type your name here:"); Label sessionIdLabel = new Label(); Label dataFromService_Name = new Label(); dataFromService_Name.setVisible(false); Label dataFromService_more = new Label(); dataFromService_more.setVisible(false); layout.addComponent(name); layout.addComponent(sessionIdLabel); layout.addComponent(dataFromService_Name); layout.addComponent(dataFromService_more); Button button = new Button("Click Me"); button.addClickListener(e -> { inputData = controller.setUserInput(name.getValue()); String sessionID = ((com.vaadin.server.VaadinServletRequest) VaadinService.getCurrentRequest()) .getHttpServletRequest().getSession().getId(); sessionIdLabel.setValue(sessionID); dataFromService_Name.setValue("Thanks, you entered: " + inputData.getName() ); dataFromService_Name.setVisible(true); dataFromService_more.setValue("Thanks, it has more data: " + inputData.getMoreData() ); dataFromService_more.setVisible(true); }); layout.addComponent(button); Button logout = new Button("Logout"); logout.addClickListener(e -> { VaadinService.getCurrentRequest().getWrappedSession().invalidate(); new SecurityContextLogoutHandler() .logout(((com.vaadin.server.VaadinServletRequest) VaadinService.getCurrentRequest()) .getHttpServletRequest(), null, null); Page.getCurrent().setLocation("/"); }); layout.addComponent(logout); setContent(layout); } @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) public static class MyUIServlet extends SpringVaadinServlet { } }
- line 82-86: Add a logout button to invalidate the session.
6. Demo Secured Vaadin Web Application
Execute Jetty:run
and go to http://localhost:8080
. Enter your valid username and password.
Enter a name and then click the Click Me
button several times.
Note: For different outputs, enter different names.
Click the logout button. Enter an invalid username and password.
Note: Enter your valid username again, then verify that the SessionId
value is updated.
7. Summary
In this example, we built a web application and secured it with a login page. The web application was created via the Vaadin Maven archetype and then modified with the MVC pattern, and then added a login page via Spring Security framework.
8. Download the Source Code
This example consists of a secured Vaadin web application.
You can download the full source code of this example here: Vaadin Spring Security Example
how can we achieve this integrated with spring boot