Custom Spring Security Login with Vaadin 10

2019-05-16 11:55发布

问题:

i am trying to use Vaadin along with spring boot and i'm using spring-security as well. this is the configuration that i've done in the WebSecurityConfigurerAdapter class.

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
                http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/VAADIN/**", "/PUSH/**", "/UIDL/**", "/login", "/login/**", "/error/**", "/accessDenied/**", "/vaadinServlet/**","/myui/**","/test/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll().defaultSuccessUrl("/myui", true).and()
                .sessionManagement().sessionAuthenticationStrategy(sessionControlAuthenticationStrategy());
    }

and this is my login view .

@Route("login")
@Theme(value = Lumo.class, variant = Lumo.DARK)

public class LoginForm extends Div {

    public LoginForm(){
        init();
    }

    public void init(){
        FormLayout nameLayout = new FormLayout();

        TextField username = new TextField();
        username.setLabel("UserName");
        username.setPlaceholder("username");

        PasswordField passwordField = new PasswordField();
        passwordField.setLabel("password");
        passwordField.setPlaceholder("*****");

        Button loginButton = new Button("login");

        loginButton.addClickListener(event -> {
        });

        nameLayout.add(username,passwordField);

        add(nameLayout);
    }
}

the problem that i'm having is i always see an empty page when user is redirected to /login but after inspecting the Html page i can see that there are vaadin elements but they doesn't appear in the browser.

回答1:

This is my working configuration:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable() // CSRF handled by Vaadin
            .exceptionHandling()
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                .accessDeniedPage("/accessDenied")
            .and()
            .authorizeRequests()
                // allow Vaadin URLs without authentication
                .regexMatchers("/frontend/.*", "/VAADIN/.*", "/login.*", "/accessDenied.*").permitAll()
                .regexMatchers(HttpMethod.POST, "/\\?v-r=.*").permitAll()
                // deny other URLs until authenticated
                .antMatchers("/**").fullyAuthenticated();
}

All requests are redirected to login view until authenticated. I didn't try @Push so far, so it may needs additional URLs to be always allowed.

With Firefox developer tool, you can inspect XHR calls in the console. If any of the XHR calls fail with 403 or something, you may need to adapt your security configuration.



回答2:

package com.example.test.spring.security;

import com.vaadin.flow.server.ServletHelper;
import com.vaadin.flow.shared.ApplicationConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import javax.servlet.http.HttpServletRequest;
import java.util.stream.Stream;


@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/VAADIN/**", "/HEARTBEAT/**", "/UIDL/**", "/resources/**"
                        , "/login", "/login**", "/login/**", "/manifest.json", "/icons/**", "/images/**",
                        // (development mode) static resources
                        "/frontend/**",
                        // (development mode) webjars
                        "/webjars/**",
                        // (development mode) H2 debugging console
                        "/h2-console/**",
                        // (production mode) static resources
                        "/frontend-es5/**", "/frontend-es6/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .successForwardUrl("/something")
                .and()
                .logout()
                .permitAll();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user =
                User.withDefaultPasswordEncoder()
                        .username("user")
                        .password("password")
                        .roles("USER")
                        .build();

        return new InMemoryUserDetailsManager(user);
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                // Vaadin Flow static resources
                "/VAADIN/**",

                // the standard favicon URI
                "/favicon.ico",

                // web application manifest
                "/manifest.json",

                // icons and images
                "/icons/**",
                "/images/**",

                // (development mode) static resources
                "/frontend/**",

                // (development mode) webjars
                "/webjars/**",

                // (development mode) H2 debugging console
                "/h2-console/**",

                // (production mode) static resources
                "/frontend-es5/**", "/frontend-es6/**");
    }


    static boolean isFrameworkInternalRequest(HttpServletRequest request) {
        final String parameterValue = request.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER);
        return parameterValue != null
                && Stream.of(ServletHelper.RequestType.values()).anyMatch(r -> r.getIdentifier().equals(parameterValue));
    }

}

after changing the web configuration to this i was able to fix the problem