Spring Security a prihlasovanie cez web s pevným používateľom

V úvodných fázach projektu sme potrebovali “napevno” prihlasovať používateľa do Spring Security. Pri požiadavke cez HTTP musel zbehnúť celý mechanizmus prihlasovania, akurát samotný login používateľa sa nikde nezadával: jednoducho bol napevno daný v kóde.

Konfigurácia je dvojfázová a prebieha v podtriede WebSecurityConfigurerAdapter, ktorá má zároveň anotáciu @EnableWebSecurity.

  • nakonfigurujeme globálneho správcu autentifikácií AuthenticationManager
  • nakonfigurujeme HttpSecurity

Konfigurácia zabezpečenia HTTP

Do objektu HttpSecurity stačí dodať nový filter:

http.addFilter(new HardwiredUserAuthenticationFilter(PRE_AUTH_USER, authenticationManager()));

Vlastný filter pre pevného používateľa

Tento špeciálny ServletFilter sa postará o získanie principala, ktorý sa posunie do mašinérie Spring Security. V našom prípade si filter napíšeme sami, kde oddedíme od AbstractPreAuthenticatedProcessingFilter:

public class HardwiredUserAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {

    private final String user;

    public HardwiredUserAuthenticationFilter(String user, AuthenticationManager authenticationManager) {
        this.user = user;
        setAuthenticationManager(authenticationManager);
    }

    @Override
    protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
        return this.user;
    }

    @Override
    protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
        return "N/A";
    }
}

Náš filter potrebuje objekt pre správu autentifikácií AuthenticationManager, a potrebuje vrátiť dve veci:

  • meno používateľa z metódy getPreAuthenticatedPrincipal()
  • a prihlasovacie heslo z getPreAuthenticatedCredentials(), ktoré budeme ignorovať

Alternatíva: filter pre meno používateľa z hlavičky požiadavky HTTP

Alternatívou je použiť RequestHeaderAuthenticationFilter, ktorý načítava používateľa z HTTP požiadavky, ale postup konfigurácie ostáva rovnaký.

Konfigurácia globálneho správcu autentifikácií AuthenticationManager

V tomto prípade je konfigurácia zložitejšia. Najprv vytvoríme inštanciu prihlasovača PreAuthenticatedAuthenticationProvider, ktorého asociujeme so správcom autentifikácií. Ten však bude potrebovať spravovať aj podrobnosti o používateľovi, teda objekt typu UserDetails.

Informáciu o detailoch poskytne v našom prípade vlastná implementácia DatabaseUserDetailsService, ktorá môže preberať dáta napr. z Postgre. Medzi službou pre detaily používateľa a našim PreAuthenticatedAuthenticationProvider potrebujeme medzikrok: objekt AuthenticationUserDetailsService, ktorý získa používateľské detaily na základe autentifikačného tokenu. Najjednoduchšia možnosť je využiť UserDetailsByNameServiceWrapper, ktorý obalí službu pre detaily.

private void configurePreAuth(AuthenticationManagerBuilder auth) {
    AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthUserDetailsService
            = new UserDetailsByNameServiceWrapper(userDetailsService());

    PreAuthenticatedAuthenticationProvider preAuthProvider = new PreAuthenticatedAuthenticationProvider();
    preAuthProvider.setPreAuthenticatedUserDetailsService(preAuthUserDetailsService);

    auth.authenticationProvider(preAuthProvider);
}

Výsledný kód

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private static final String PRE_AUTH_USER = "admin";

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService())
        configurePreAuth(auth);
    }

    @Bean
    public DatabaseUserDetailsService userDetailsService() {
        return new DatabaseUserDetailsService();
    }

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

    private void configurePreAuth(AuthenticationManagerBuilder auth) {
        AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthUserDetailsService
                = new UserDetailsByNameServiceWrapper(userDetailsService());

        PreAuthenticatedAuthenticationProvider preAuthProvider = new PreAuthenticatedAuthenticationProvider();
        preAuthProvider.setPreAuthenticatedUserDetailsService(preAuthUserDetailsService);

        auth.authenticationProvider(preAuthProvider);
    }

    private void configurePreAuth(HttpSecurity http) throws Exception {
        http.addFilter(new HardwiredUserAuthenticationFilter(PRE_AUTH_USER, authenticationManager()));
    }

}

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *