web-dev-qa-db-fra.com

Spring Security à l'aide d'en-têtes HTTP

J'essaie d'ajouter de la sécurité à mon application Spring Boot. Mon application actuelle utilise des contrôleurs REST et chaque fois que je reçois une demande GET ou POST, je lis l'en-tête HTTP pour récupérer l'utilisateur et le mot de passe afin de les valider par rapport au fichier de propriétés que j'ai stocké tous mes utilisateurs. Je veux changer cela en utilisant Spring Security et voici ce que j'ai obtenu jusqu'à présent:

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/index.html").permitAll()
            .antMatchers("/swagger-ui.html").hasRole("ADMIN")
            .anyRequest().authenticated();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("admin").password("password").roles("ADMIN").build());
    }
}

Comment puis-je dire à la méthode configure que les informations d'identification de l'utilisateur doivent être extraites de l'en-tête et non d'un formulaire de connexion?

6
Chayma Atallah

Vous devez éviter d'utiliser par défaut org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter car il obtient le nom d'utilisateur et le mot de passe fournis par le client à partir des paramètres de votre demande et vous devez vraiment les obtenir à partir des en-têtes.

Donc, vous devez écrire un AuthenticationFilter personnalisé étendu UsernamePasswordAuthenticationFilter pour modifier son comportement en fonction de vos besoins:

public class HeaderUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    /**
     * 
     */
    public HeaderUsernamePasswordAuthenticationFilter() {
        super();
        this.setFilterProcessesUrl("/**");
        this.setPostOnly(false);
    }

    /* (non-Javadoc)
     * @see org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#obtainPassword(javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected String obtainPassword(HttpServletRequest request) {
        return request.getHeader(this.getPasswordParameter());
    }

    /* (non-Javadoc)
     * @see org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#obtainUsername(javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected String obtainUsername(HttpServletRequest request) {
        return request.getHeader(this.getPasswordParameter());
    }   

}

Cet exemple de filtre étend org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter écoute chaque demande et obtient username et password des en-têtes au lieu de parameters.

Ensuite, vous devez modifier la configuration de cette façon, en définissant votre filtre sur la position UsernamePasswordAuthenticationFilter:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterAt(
                new HeaderUsernamePasswordAuthenticationFilter(), 
                UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
            .antMatchers("/index.html").permitAll()
            .antMatchers("/swagger-ui.html").hasRole("ADMIN")
            .anyRequest().authenticated();
    }
3
jlumietu

L'authentification en mémoire servirait votre objectif

@Configuration
@EnableWebMvc
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("user1").password("password1").roles("USER")
        .and()
        .withUser("user2").password("password2").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.httpBasic();   
    }

}
2
Pete T

l'ajout minimal de code consiste à définir un filtre et à l'ajouter à la configuration de sécurité, comme smth

XHeaderAuthenticationFilter.Java

@Component
public class XHeaderAuthenticationFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request,
                                HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {

    String xAuth = request.getHeader("X-Authorization");

    User user = findByToken(xAuth);

    if (user == null) {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token invalid");
    } else {
        final UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

        filterChain.doFilter(request, response);
    }
}

//need to implement db user validation...
private User findByToken(String token) {
    if (!token.equals("1234"))
        return null;

    final User user = new User(
            "username",
            "password",
            true,
            true,
            true,
            true,
            Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));

    return user;
}
}

SecurityConfig.Java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .csrf().disable()
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .exceptionHandling()
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
            .and()
            .addFilterBefore(new XHeaderAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

une autre approche consiste à utiliser AOP de spring pour définir l'annotation d'une logique à exécuter avant d'entrer dans la méthode du contrôleur annoté

0
shahaf