Spring Security

Το 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();
                            }
                        }
                
            
Πηγές