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()));
}
}