Spring Boot Security with Vaadin Login

I am trying to create an application based on Spring Boot (1.2.7.RELEASE) and Vaadin (7.6.3). My problem is that I cannot integrate Spring Security with Vaadin. I want custom Vaadin to create LoginScreen and Spring Security control. My project setup is as follows:

@Configuration @EnableWebSecurity public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(). exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).accessDeniedPage("/accessDenied") .and().authorizeRequests() .antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/login", "/login/**", "/error/**", "/accessDenied/**", "/vaadinServlet/**").permitAll() .antMatchers("/authorized", "/**").fullyAuthenticated(); } } 

And here is my Vaadin login interface

  @SpringUI(path = "/login") @Title("LoginPage") @Theme("valo") public class LoginUI extends UI { TextField user; PasswordField password; Button loginButton = new Button("Login", this::loginButtonClick); private static final String username = "username"; private static final String passwordValue = "test123"; @Override protected void init(VaadinRequest request) { setSizeFull(); user = new TextField("User:"); user.setWidth("300px"); user.setRequired(true); user.setInputPrompt("Your username"); password = new PasswordField("Password:"); password.setWidth("300px"); password.setRequired(true); password.setValue(""); password.setNullRepresentation(""); VerticalLayout fields = new VerticalLayout(user, password, loginButton); fields.setCaption("Please login to access the application"); fields.setSpacing(true); fields.setMargin(new MarginInfo(true, true, true, false)); fields.setSizeUndefined(); VerticalLayout uiLayout = new VerticalLayout(fields); uiLayout.setSizeFull(); uiLayout.setComponentAlignment(fields, Alignment.MIDDLE_CENTER); setStyleName(Reindeer.LAYOUT_BLUE); setFocusedComponent(user); setContent(uiLayout); } public void loginButtonClick(Button.ClickEvent e) { //authorize/authenticate user //tell spring that my user is authenticated and dispatch to my mainUI } } 

When I launch my application, Spring redirects me to my login interface, which is good.

But I do not know how to authenticate the user with respect to the Spring security mechanism and send it to my main interface.

I also run into a problem with csrf tokens if I don't disable csrf. I get crfs token - this is an exception. I found many examples to solve these problems, but there is no solution with Vaadin.

Thanks for the help.

+8
java spring-boot spring-security vaadin7
source share
2 answers

After a week of struggle and research, I was able to get this job done. It was very tiring because there was a lot of information and solutions on the Internet, most of which used xml based configuration or JSP based login, so far I could not find another solution without xml configuration file using Vaadin infrastructure to create user login page.

I cannot guarantee that this is best practice or a simple solution. Moreover, I did not evaluate every part of it, the registration mechanism works as far as I can see, but maybe there may be some problems that I have not yet discovered.

Perhaps this will help someone who is facing the same problem, so I will post my answer here.

First of all, my securityConfig:

 @Resource(name = "authService") private UserDetailsService userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(). exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).accessDeniedPage("/accessDenied") .and().authorizeRequests() .antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/login", "/login/**", "/error/**", "/accessDenied/**", "/vaadinServlet/**").permitAll() .antMatchers("/authorized", "/**").fullyAuthenticated(); } @Bean public DaoAuthenticationProvider createDaoAuthenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailsService); provider.setPasswordEncoder(passwordEncoder()); return provider; } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } 

You need to disable crsf, but this is not a problem, since vaadin has its own crsf protection.

In addition, you need to allow some URIs, so vaadin can access its resources: /VAADIN/** absolutely necessary, I also recommend allowing /vaadinServlet/** , /PUSH/** and /HEARTBEAT/** , but this Depends on which parts of Vaadin you are using.

My second UserDetailsService :

 @Service("authService") public class AuthService implements UserDetailsService { @Autowired CustomUserRepository userRepository; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { CustomUser user = userRepository.findCustomUserByUserName(userName); return user; } } 

DaoAuthenticationProvider uses the UserDetails ' loadUserByUserName to get a class object that implements the UserDetails interface. Keep in mind that each attribute described in UserDetailsInterface must not be null, otherwise you will get a NullPointerException , later added by DaoAuthenticationProvider .

I created a JPA object that implements the UserDetails interface:

 @Entity public class CustomUser implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; @ManyToMany(fetch = FetchType.EAGER) Collection<Authorities> authorities; String password; String userName; Boolean accountNonExpired; Boolean accountNonLocked; Boolean credentialsNonExpired; Boolean enabled; @Autowired @Transient BCryptPasswordEncoder passwordEncoder; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return userName; } @Override public boolean isAccountNonExpired() { return accountNonExpired; } @Override public boolean isAccountNonLocked() { return accountNonLocked; } @Override public boolean isCredentialsNonExpired() { return credentialsNonExpired; } @Override public boolean isEnabled() { return enabled; } public void setId(Long id) { this.id = id; } public void setAuthorities(Collection<Authorities> authorities) { this.authorities = authorities; } public void setPassword(String password) { this.password = passwordEncoder.encode(password); } public void setUserName(String userName) { this.userName = userName; } public void setAccountNonExpired(Boolean accountNonExpired) { this.accountNonExpired = accountNonExpired; } public void setAccountNonLocked(Boolean accountNonLocked) { this.accountNonLocked = accountNonLocked; } public void setCredentialsNonExpired(Boolean credentialsNonExpired) { this.credentialsNonExpired = credentialsNonExpired; } public void setEnabled(Boolean enabled) { this.enabled = enabled; } } 

Plus to the powers:

 @Entity public class Authorities implements GrantedAuthority { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; String authority; @Override public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } } 

Obviously, you will have to store some user data in the database before authentication works.

In Vaadin, I could not get it to work using one user interface with different views, so in the end I used two user interfaces for login, and the other for the main application.

In Vaadin, I can set the URI path in class annotation:

 @SpringUI(path = "/login") @Title("LoginPage") @Theme("valo") public class LoginUI extends UI { //... } 

In this configuration, my login screen is available in localhost:port/login and my main application is in localhost:port/main .

I approach the user programmatically using the button.click method in my loginUI:

 Authentication auth = new UsernamePasswordAuthenticationToken(userName.getValue(),password.getValue()); Authentication authenticated = daoAuthenticationProvider.authenticate(auth); SecurityContextHolder.getContext().setAuthentication(authenticated); //redirect to main application getPage().setLocation("/main"); 

I hope this has helped some of you.

+21
source share

As an alternative to this approach, you can also rely on vaadin4spring , an β€œunofficial” set of extensions for further integration of Vaadin and Spring .

It currently offers two ways to integrate Spring Security, which seems to work fine (even if they don't work for you, the code samples should give you enough information to write custom integration code).

+3
source share

All Articles