Το Spring Security είναι ένα Java / Java EE framework, το οποίο παρέχει τη δυνατότητα αυθεντικοποίησης (authentication), εξουσιοδότησης (authorization) και άλλες λειτουργίες ασφάλειας για enterprise εφαρμογές. Το project ξεκίνησε το 2003 ως Acegi Security και ύστερα ενσωματώθηκε στο Spring portfolio , ως επίσημο Spring sub-project.
Για να ενεργοποιήσουμε το Spring Security, μπορούμε να χρησιμοποιήσουμε Java Configuration. Το configuration δημιουργεί ένα Servlet Filter, γνωστό ως springSecurityFilterChain, το οποίο είναι υπεύθυνο για την προστασία της εφαρμογής (προστασία των URLs, validation του ονόματος χρήστη και του κωδικού, κ.α.). Το πιο απλό παράδειγμα configuration δίνεται παρακάτω.
@EnableWebSecurity
public class WebSecurityConfig implements WebMvcConfigurer {
@Bean
public UserDetailsService userDetailsService() throws Exception{
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
return manager;
}
}
Ο παραπάνω κώδικας είναι μικρός, αλλά κάνει πολλά.
HttpSecurity
Η κλάση WebSecurityConfigurerAdapter παρέχει τη μέθοδο configure(HttpSecurity http). Σε αυτήν ορίζουμε πια urls της εφαρμογής πρέπει, να είναι ασφαλή, αν οι χρήστες πρέπει, να αυθεντικοποιηθούν, για να έχουν πρόσβαση σε αυτά κ.α.
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
}
Το παραπάνω default configuration :
Login φόρμα
Το default configuration δεν ορίζει ρήτα ένα URL, για τη φόρμα και δημιουργεί μια αυτόματα. Εάν θέλουμε, να παρέχουμε τη δικιά μας φόρμα, χρειάζεται το ακόλουθο configuration :
public configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
Παραπάνω, ορίζουμε ότι η login φόρμα μας βρίσκεται στο URL /login και επιτρέπουμε σε όλους τους χρήστες(και σε αυτούς, που δεν έχουν αυθεντικοποιηθεί) την πρόσβαση.
Εξουσιοδότηση αιτημάτων
Μπορούμε, να ορίσουμε σε ποια URLS επιτρέπεται, να έχουν πρόσβαση οι χρήστες και τους τύπους των χρηστών.
public configure(HttpSecurity http) throws Exception{
http
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin();
}
Διαχείριση αποσύνδεσης
Όταν χρησιμοποιούμε το WebSecurityConfigurerAdapter, η δυνατότητα αποσύνδεσης παρέχεται αυτόματα. Το default URL για να αποσυνδεθεί ο χρήστης, είναι το /logout. Μπορούμε, να προσαρμόσουμε το configuration, ανάλογα με τις ανάγκες μας:
public configure(HttpSecurity http) throws Exception{
http
.logout()
.logoutUrl("/my/logout")
.logoutSuccessUrl("/my/index")
.logoutSuccessHandler(logoutSuccessHandler)
.invalidateHttpSession(true)
.deleteCookies(cookieNamesToClear)
.and()
...
}
In-Memory Αυθεντικοποίηση
Μπορούμε να επιλέξουμε, οι χρήστες να αποθηκεύονται στην μνήμη
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
}
Δημιουργούμε δύο χρήστες : τον χρήστη user με κωδικό password και ρόλο USER και τον χρήστη user με κωδικό password και ρόλους USER, ADMIN.
JDBC Αυθεντικοποίηση
Μπορούμε να αποθηκεύσουμε τους χρήστες στη βάση δεδομένων, αρκεί να έχουμε ορίσει ένα Datasource στην εφαρμογή.
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth
.jdbcAuthentication()
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username, password, is_active from users where username=?")
.authoritiesByUsernameQuery("select username, role from authorities where username=?");
}
@Bean(name = "passwordEncoder")
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}