Introduction

Application security includes “authentication” and “authorization”:

  • “Authentication” is the process of establishing a principal is who they claim to be(a “principal” generally means a user, device or some other system which can perform an action in your application).
  • “Authorization” refers to the process of deciding whether a principal is allowed to perform an action within your application.

Spring Security provides a deep set of authorization capabilities, they are divided into mainly three areas:

  • authorizing web requests
  • authorizing whether methods can be invoked
  • authorizing access to individual domain object instances

maven dependencies:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.0.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.0.6.RELEASE</version>
</dependency>

The major building blocks of Spring Security:

  • SecurityContextHolder, to provide access to SecurityContext.
  • SecurityContext, to hold the Authentication and possibly request-specific security imformation.
  • Authentication, to represent the principal in a Spring Security-specific manner.
  • GrantedAuthority, to reflect the application-wide permissions granted to a principal.
  • UserDetails, to provide the necessary information to build an Authentication object from your application’s DAOs or other source of security data.
  • UserDetailsService, to create a UserDetails when passed in a String-based username( or certificate ID or the like).

The authentication process within Spring Security:

  1. The username and passwod are obtained and combined into an instance of UsernamePasswordAuthenticationToken (an instance of Authentication interface)
  2. The token is passed to an instance of AuthenticationManager for validation.
  3. The AuthenticationManager returns a fully populated Authentication instance on successful authentication.
  4. The security context is established by calling SecurityContextHolder.getContext().setAuthentication(...), passing in the authentication object.

Integrate with Spring MVC

Refister the springSecurityFilterChain Filter for every URL in application. After that we would ensure that WebSecurityConfig was loaded in out existing ApplicationInitializer.

public class MvcWebApplicationInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { WebSecurityConfig.class };
    }

    // ... other overrides ...
}

HttpSecurity

Implement interface WebSecurityConfigurerAdapter and override the config method like what below do:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()                                                                1
            .antMatchers("/resources/**", "/signup", "/about").permitAll()                  2
            .antMatchers("/admin/**").hasRole("ADMIN")                                      3
            .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")            4
            .anyRequest().authenticated()                                                   5
            .and()
        // ...
        .formLogin();
}

If you do not specify a login page, Spring Security will generate one automatically.

Handling Logouts

Spring Security logout progress:

  • Invalidating the HTTP Session
  • Cleaning up any RememberMe authentication that was configured
  • Clearing the SecurityContextHolder
  • Redirect to /login?logout
    You can custom logout action by the config method as well.
LogoutHandler

Generally, LogoutHandler implementations indicate classes that are able to participate in logout handling. They are expected to be invoked to perform necessary clean-up. As such they should not throw exceptions. Various implementations are provided:

  • PersistentTokenBasedRememberMeServices
  • TokenBasedRememberMeServices
  • CookieClearingLogoutHandler
  • CsrfLogoutHandler
  • SecurityContextLogoutHandler
LogoutSuccessHandler

Called after a successful logout by the LogoutFilter, to handle e.g redirection or forwarding to the appropriate destination.
implementations:

  • SimpleUrlLogoutSuccessHandler
  • HttpStatusReturningLogoutSuccessHandler

Authentication

JDBC Authentication

Java config example as below:

@Autowired
private DataSource dataSource;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    // ensure the passwords are encoded properly
    UserBuilder users = User.withDefaultPasswordEncoder();
    auth
        .jdbcAuthentication()
            .dataSource(dataSource)
            .withDefaultSchema()
            .withUser(users.username("user").password("password").roles("USER"))
            .withUser(users.username("admin").password("password").roles("USER","ADMIN"));
}
Custom Authentication
  1. AuthenticationProvider
    You can define custom authentication by exposing a custom AuthenticationProvider as a bean.For example, the following will customize authentication assuming that SpringAuthenticationProvider implements AuthenticationProvider:
    @Bean
    public SpringAuthenticationProvider springAuthenticationProvider() {
     return new SpringAuthenticationProvider();
    }
    
  2. UserDetailsService
    You can define custom authentication by exposing a custom UserDetailsService as a bean. For example, the following will customize authentication assuming that SpringDataUserDetailsService implements UserDetailsService:
    @Bean
    public SpringDataUserDetailsService springDataUserDetailsService() {
     return new SpringDataUserDetailsService();
    }
    
    You can also customize how passwords are encoded by exposing a PasswordEncoder as a bean. For example, if you use bcrypt you can add a bean definition as shown below:
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
     return new BCryptPasswordEncoder();
    }
    

Multiple HttpSecurity

We can configure multiple HttpSecurity instances just as we can have multiple blocks. The key is to extend the WebSecurityConfigurationAdapter multiple times.

@EnableWebSecurity
public class MultiHttpSecurityConfig {
    @Bean
    public UserDetailsService userDetailsService() throws Exception {
        // ensure the passwords are encoded properly
        UserBuilder users = User.withDefaultPasswordEncoder();
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(users.username("user").password("password").roles("USER").build());
        manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
        return manager;
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/**")
                .authorizeRequests()
                    .anyRequest().hasRole("ADMIN")
                    .and()
                .httpBasic();
        }
    }

    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

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

Method Security

From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. It provides support for JSR-250 annotation security as well as the framework’s original @Secured annotation. From 3.0 you can also make use of new expression-based annotations.

EnableGlobalMethodSecurity

We can enable annotation-based security using the @EnableGlobalMethodSecurity annotation on any @Configuration instance. For example, the following would enable Spring Security’s @Secured annotation.

@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}

Adding an annotation to a method (on a class or interface) would then limit the access to that method accordingly. Spring Security’s native annotation support defines a set of attributes for the method. These will be passed to the AccessDecisionManager for it to make the actual decision:

public interface BankService {

@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account readAccount(Long id);

@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
public Account[] findAccounts();

@Secured("ROLE_TELLER")
public Account post(Account account, double amount);
}

Support for JSR-250 annotations can be enabled using

@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
// ...
}

These are standards-based and allow simple role-based constraints to be applied but do not have the power Spring Security’s native annotations. To use the new expression-based syntax, you would use

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// ...
}

the java code would be

public interface BankService {

@PreAuthorize("isAnonymous()")
public Account readAccount(Long id);

@PreAuthorize("isAnonymous()")
public Account[] findAccounts();

@PreAuthorize("hasAuthority('ROLE_TELLER')")
public Account post(Account account, double amount);
}

full list:
@PreAuthorize
@PostAuthorize
@PostFilter- filter the result
@PreFilter:filter the param

posted on 2018-08-04 14:19  浮舟z  阅读(209)  评论(0编辑  收藏  举报