¿Cómo asegurar la aplicación de flujo Vaadin con Spring Security

SrThompson:

Estoy tratando de integrar vaadin 10 con la seguridad de muelle (usando la base del proyecto de resorte proporcionada por vaadin), y yo estoy confundido sobre la forma en que interactúan con exactitud. Si voy a una URL protegida (en este ejemplo, "/ about") escribiéndola directamente en el navegador, los espectáculos de la página de inicio de sesión para arriba. Si voy a la misma URL haciendo clic en un enlace desde la interfaz de usuario, los espectáculos página hasta incluso si no estoy autenticados. Así que supongo que Vaadin no está pasando por cadena de filtros de primavera de Seguridad, pero entonces, ¿cómo puedo proteger mis recursos dentro de la interfaz de usuario, y cómo puedo compartir el usuario autenticado entre vaadin y la primavera? ¿Se supone que implementar la seguridad dos veces? La documentación disponible no parece cubrir esto, y todos los vínculos de internet tiene ejemplos con Vaadin 7-8, que nunca he utilizado y parece que funciona de forma diferente a partir de 10 +.

¿Alguien sabe cualquier recurso sobre esto, o puede que me ilumine sobre cómo funciona todo esto en conjunto para que pueda saber lo que estoy haciendo?

Aquí está mi configuración de seguridad:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String[] ALLOWED_GET_URLS = {
        "/",
        //"/about",
        "/login/**",
        "/frontend/**",
        "/VAADIN/**",
        "/favicon.ico"
    };

    private static final String[] ALLOWED_POST_URLS = {
        "/"
    };

    //@formatter:off
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .disable()
            .authorizeRequests()
                .mvcMatchers(HttpMethod.GET, ALLOWED_GET_URLS)
                    .permitAll()
                .mvcMatchers(HttpMethod.POST, ALLOWED_POST_URLS)
                    .permitAll()
                .anyRequest()
                    .fullyAuthenticated()
             .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll()
            .and()
                .logout()
                    .logoutSuccessUrl("/")
                    .permitAll();
    }
    //@formatter:on

}
Youness:

Utilizando el flujo Vaadin (12.0.2), Primavera de arranque Motor de arranque (2.0.2.RELEASE) y el muelle de arranque de seguridad, básicamente, me encontré con la que se autoriza basan en papel / autoridad de estas formas;

Ruta / Contexto papel / autoridad gerencia basada

  • Spring Security (HttpSecurity)
  • Vaadin API (BeforeEnterListener y la Ruta / Navegación API)

papel de la unidad de negocio / gestión de la autoridad

  • Dentro del código utilizando el método HttpServletRequest.isUserInRole

Vamos a empezar con un ejemplo simple de configuración de Seguridad de la primavera;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig
        extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // CSRF is handled by Vaadin: https://vaadin.com/framework/security
                .exceptionHandling().accessDeniedPage("/accessDenied")
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
                .and().logout().logoutSuccessUrl("/")
                .and()
                .authorizeRequests()
                // allow Vaadin URLs and the login URL without authentication
                .regexMatchers("/frontend/.*", "/VAADIN/.*", "/login.*", "/accessDenied").permitAll()
                .regexMatchers(HttpMethod.POST, "/\\?v-r=.*").permitAll()
                // deny any other URL until authenticated
                .antMatchers("/**").fullyAuthenticated()
            /*
             Note that anonymous authentication is enabled by default, therefore;
             SecurityContextHolder.getContext().getAuthentication().isAuthenticated() always will return true.
             Look at LoginView.beforeEnter method.
             more info: https://docs.spring.io/spring-security/site/docs/4.0.x/reference/html/anonymous.html
             */
        ;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("admin").password("$2a$10$obstjyWMAVfsNoKisfyCjO/DNfO9OoMOKNt5a6GRlVS7XNUzYuUbO").roles("ADMIN");// user and pass: admin 
    }

    /**
    * Expose the AuthenticationManager (to be used in LoginView)
    * @return
    * @throws Exception
    */
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

Como se puede ver, no he especificado ningún permiso basado en papel en cualquiera de mis puntos de vista enrutados (anotado con @Route) todavía. Lo que voy a hacer es si tengo una vista enrutada, registrando un BeforeEnterListener cuando (la vista enrutado) se está construyendo, y revisará el papel / privilegio necesario allí.

El siguiente es un ejemplo para comprobar si el usuario tiene papel ADMIN antes de navegar a admin-utils ver;

@Route(value = "admin-utils")
public class AdminUtilsView extends VerticalLayout { 
@Autowired
private HttpServletRequest req;
...
    AdminUtilsView() {
        ...
        UI.getCurrent().addBeforeEnterListener(new BeforeEnterListener() {
            @Override
            public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
                if (beforeEnterEvent.getNavigationTarget() != DeniedAccessView.class && // This is to avoid a
                        // loop if DeniedAccessView is the target
                        !req.isUserInRole("ADMIN")) {
                    beforeEnterEvent.rerouteTo(DeniedAccessView.class);
                }
            }
        });
    }
}

En caso de que el usuario no tiene la función de administrador, (s) que se dirigirá a DeniedAccessView ya que está permitido para todos en la configuración de la primavera de Seguridad.

@Route(value = "accessDenied")
public class DeniedAccessView
        extends VerticalLayout {
    DeniedAccessView() {
        FormLayout formLayout = new FormLayout();
        formLayout.add(new Label("Access denied!"));
        add(formLayout);
    }
}

En el ejemplo anterior (AdminUtilsView), también se puede ver un caso de uso para HttpServletRequest.isUserInRole () en el código de Vaadin por Autowiring HttpServletRequest.

Resumen: Si su punto de vista tiene una ruta, utilice BeforeEnterListener para autorizar la solicitud en primer lugar, de lo contrario utilizar comparadores de seguridad (por ejemplo, la primavera o regexMatchers antMatchers) para los servicios de descanso y etc.

NOTA: El uso de ambos matcher las reglas de ruta Vaadin y Spring Security juntos por la misma regla podría ser un poco retorcido y no sugieren que (que hace que algunos bucles internos en Vaadin; por ejemplo, imaginemos que tenemos una vista enrutado con / y un punto de vista la entrada en la primavera de Seguridad para el / la vista con un papel necesario. Si un usuario es que no contengan esas clases, y (s) que se encamina / navegado a dicha página (usando Vaadin API de enrutamiento), Vaadin intenta abrir la vista asociada con la ruta, mientras que la primavera evita seguridad que debido a la función que falta).

Además, creo que, utilizando Vaadin fluya API de navegación una buena práctica antes de cambios de ruta o la navegación por el usuario a un punto de vista diferente / contexto sería para comprobar el papel / autoridad requerida.

Por otra parte, para tener un ejemplo del uso AuthenticationManager en Vaadin, podemos tener un LoginView basado Vaadin similar a;

@Route(value = "login")
public class LoginView
        extends FlexLayout implements BeforeEnterObserver {

    private final Label label;
    private final TextField userNameTextField;
    private final PasswordField passwordField;

    /**
    * AuthenticationManager is already exposed in WebSecurityConfig
    */
    @Autowired
    private AuthenticationManager authManager;

    @Autowired
    private HttpServletRequest req;

    LoginView() {
        label = new Label("Please login...");

        userNameTextField = new TextField();
        userNameTextField.setPlaceholder("Username");
        UiUtils.makeFirstInputTextAutoFocus(Collections.singletonList(userNameTextField));

        passwordField = new PasswordField();
        passwordField.setPlaceholder("Password");
        passwordField.addKeyDownListener(Key.ENTER, (ComponentEventListener<KeyDownEvent>) keyDownEvent -> authenticateAndNavigate());

        Button submitButton = new Button("Login");
        submitButton.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> {
            authenticateAndNavigate();
        });

        FormLayout formLayout = new FormLayout();
        formLayout.add(label, userNameTextField, passwordField, submitButton);
        add(formLayout);

        // center the form
        setAlignItems(Alignment.CENTER);
        this.getElement().getStyle().set("height", "100%");
        this.getElement().getStyle().set("justify-content", "center");
    }

    private void authenticateAndNavigate() {
        /*
        Set an authenticated user in Spring Security and Spring MVC
        spring-security
        */
        UsernamePasswordAuthenticationToken authReq
                = new UsernamePasswordAuthenticationToken(userNameTextField.getValue(), passwordField.getValue());
        try {
            // Set authentication
            Authentication auth = authManager.authenticate(authReq);
            SecurityContext sc = SecurityContextHolder.getContext();
            sc.setAuthentication(auth);

            /*
            Navigate to the requested page:
            This is to redirect a user back to the originally requested URL – after they log in as we are not using
            Spring's AuthenticationSuccessHandler.
            */
            HttpSession session = req.getSession(false);
            DefaultSavedRequest savedRequest = (DefaultSavedRequest) session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
            String requestedURI = savedRequest != null ? savedRequest.getRequestURI() : Application.APP_URL;

            this.getUI().ifPresent(ui -> ui.navigate(StringUtils.removeStart(requestedURI, "/")));
        } catch (BadCredentialsException e) {
            label.setText("Invalid username or password. Please try again.");
        }
    }

    /**
    * This is to redirect user to the main URL context if (s)he has already logged in and tries to open /login
    *
    * @param beforeEnterEvent
    */
    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        //Anonymous Authentication is enabled in our Spring Security conf
        if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) {
            //https://vaadin.com/docs/flow/routing/tutorial-routing-lifecycle.html
            beforeEnterEvent.rerouteTo("");
        }
    }
}

Y, por último, aquí está el método de cierre de sesión que se puede llamar desde un menú o un botón:

/**
 * log out the current user using Spring security and Vaadin session management
 */
void requestLogout() {
    //https://stackoverflow.com/a/5727444/1572286
    SecurityContextHolder.clearContext();
    req.getSession(false).invalidate();

    // And this is similar to how logout is handled in Vaadin 8:
    // https://vaadin.com/docs/v8/framework/articles/HandlingLogout.html
    UI.getCurrent().getSession().close();
    UI.getCurrent().getPage().reload();// to redirect user to the login page
}

Puede seguir completando la administración de funciones utilizando Spring UserDetailsService y la creación de un grano de PasswordEncoder examinado los siguientes ejemplos:

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=179561&siteId=1
Recomendado
Clasificación