Spring Security (4): custom configuration

Then the festival say, after adding a @EnableWebSecurity notes, if you need to customize some configuration is required and inheritance WebSecurityConfigurerAdapter after covering certain methods.

We look WebSecurityConfigurerAdapter in which methods can be overridden, you need to be rewritten.

(1)WebSecurity

The default is an empty method, generally will not be rewritten.

    public void configure(WebSecurity web) throws Exception { }

 

(2)HttpSecurity

The default parent code default any request requires authentication, use the default login page form-based authentication, using HTTP Basic Authentication.

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

Here are some custom wording.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //@formatter:off
        http.authorizeRequests()
            // all users have access to these urls
            .antMatchers("/resources/**", "/signup", "/about").permitAll()
            // Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN"
            .antMatchers("/admin/**").hasRole("ADMIN")
            // Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA"
            .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
            //  Any URL that starts with "/group_a/" requires the user to have both "ROLE_ADMIN" or "ROLE_GROUP_A"
            .antMatchers("/admin/**").hasAnyRole("ADMIN", "GROUP_A")
            // Any URL that has not already been matched on only requires that the user be authenticated
            .anyRequest().authenticated()
        .and().formLogin()
             // all users have access to custom login page
            .loginPage("/login").permitAll()
        .and().logout()
            // customize logout url
            .logoutUrl("/my/logout")
            // customize logout success url
            .logoutSuccessUrl("/my/index")
            // specify a custom LogoutSuccessHandler. If this is specified, logoutSuccessUrl() is ignored
            .logoutSuccessHandler(logoutSuccessHandler)
            // invalidate the HttpSession at the time of logout. This is true by default
            .invalidateHttpSession(true)
            // Adds a LogoutHandler. SecurityContextLogoutHandler is added as the last LogoutHandler by default
            .addLogoutHandler(logoutHandler)
            // Allows specifying the names of cookies to be removed on logout success
            .deleteCookies()
        .and().rememberMe()
            // Add remember me function and valid date.
            .key("uniqueAndSecret")
            .tokenValiditySeconds(60 * 60 * 24 * 7);
        //@formatter:on
    }

 

(3)AuthenticationManagerBuilder

The default is written like this:

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        this.disableLocalConfigureAuthenticationBldr = true;
    }

From the above analysis one, it is actually the default DefaultPasswordEncoderAuthenticationManagerBuilder Builder and UserDetails and UserDetailsService configured automatically.

    protected AuthenticationManager authenticationManager() throws Exception {
        if (!authenticationManagerInitialized) {
// [1]如果覆盖configure()方法,则disableLocalConfigureAuthenticationBldr为false
// [2]如果是默认的configure()方法,disableLocalConfigureAuthenticationBldr还是true configure(localConfigureAuthenticationBldr);
if (disableLocalConfigureAuthenticationBldr) { authenticationManager = authenticationConfiguration .getAuthenticationManager(); // [2] } else { authenticationManager = localConfigureAuthenticationBldr.build(); // [1] } authenticationManagerInitialized = true; } return authenticationManager; }

If covered, although they are still used DefaultPasswordEncoderAuthenticationManagerBuilder, but we can use UserDetailsManagerConfigurer (two subclasses InMemoryUserDetailsManagerConfigurer, JdbcUserDetailsManagerConfigurer ) to build UserDetailsService and UserDetails. To InMemoryUserDetailsManagerConfigurer for example, the following is the custom wording.

    @Bean
    PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //@formatter:off
        // returns InMemoryUserDetailsManagerConfigurer
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        auth.inMemoryAuthentication()
            // create a UserDetailsBuilder and add to userBuilders
            .withUser("user").password("{bcrypt}" + encoder.encode("pass")).roles("USER")
            // returns InMemoryUserDetailsManagerConfigurer
            .and()
            // create a UserDetailsBuilder again and add to userBuilders
.withUser("admin").password("{bcrypt}" + encoder.encode("pass")).roles("USER", "ADMIN"); //@formatter:on }

[Note] framework requires a password must be encrypted, so here plus the support of the relevant password encode.

 

So how to generate this code UserDetailsService and UserDetails it? Process is as follows:

[1] will be created when the call AuthenticationManagerBuilder inMemoryAuthentication () method to create InMemoryUserDetailsManagerConfigurer, call the constructor InMemoryUserDetailsManagerConfigurer InMemoryUserDetailsManager (i.e. UserDetailsService implementation class) , and ultimately through the layers of the parent class ( InMemoryUserDetailsManagerConfigurer -> UserDetailsManagerConfigurer -> UserDetailsServiceConfigurer -> AbstractDaoAuthenticationConfigurer ) provided given to AbstractDaoAuthenticationConfigurer in.

    public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
            throws Exception {
        return apply(new InMemoryUserDetailsManagerConfigurer<>());
    }
    public InMemoryUserDetailsManagerConfigurer() {
        super(new InMemoryUserDetailsManager(new ArrayList<>()));
    }
    protected AbstractDaoAuthenticationConfigurer(U userDetailsService) {
        this.userDetailsService = userDetailsService;
        provider.setUserDetailsService(userDetailsService);
        if (userDetailsService instanceof UserDetailsPasswordService) {
            this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);
        }
    }

[2] call AuthenticationManagerBuilder the Apply () method setting defaultUserDetailsService to [1] InMemoryUserDetailsManager and the [1] was added to the parent InMemoryUserDetailsManagerConfigurer AbstractConfiguredSecurityBuilder of configurers list in

    private <C extends UserDetailsAwareConfigurer<AuthenticationManagerBuilder, ? extends UserDetailsService>> C apply(
            C configurer) throws Exception {
        this.defaultUserDetailsService = configurer.getUserDetailsService();
        return (C) super.apply(configurer);
    }

[3] call parent class UserDetailsManagerConfigurer InMemoryUserDetailsManagerConfigurer of withUser () method to generate a plurality UserDetailsBuilder in userBuilders  List of

    public final UserDetailsBuilder withUser(String username) {
        UserDetailsBuilder userBuilder = new UserDetailsBuilder((C) this);
        userBuilder.username(username);
        this.userBuilders.add(userBuilder);
        return userBuilder;
    }

[4]  When the call DefaultPasswordEncoderAuthenticationManagerBuilder build () method will be called

    [4.1] call UserDetailsServiceConfigurer the configure () method

    @Override
    public void configure(B builder) throws Exception {
        initUserDetailsService();
        super.configure(builder);
    }

    [4.2]  callUserDetailsManagerConfigurer ofinitUserDetailsService () method [3]userBuilders Create User object ( UserDetails implementation class ) , andfrom [1]obtaining UserDetailsService AbstractDaoAuthenticationConfigurer, and theUserDetails into the U-serDetailsService in.

    @Override
    protected void initUserDetailsService() throws Exception {
        for (UserDetailsBuilder userBuilder : userBuilders) {
            getUserDetailsService().createUser(userBuilder.build());
        }
        for (UserDetails userDetails : this.users) {
            getUserDetailsService().createUser(userDetails);
        }
    }

 

Here are some custom writing:

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //@formatter:off
        // returns InMemoryUserDetailsManagerConfigurer
        auth.inMemoryAuthentication()
            // create a UserBuilder and add to userBuilders
            .withUser("user").password("password").roles("USER")
            // returns InMemoryUserDetailsManagerConfigurer
            .and()
            // create a UserBuilder again and add to userBuilders
            .withUser("admin").password("password").roles("USER", "ADMIN");
        //@formatter:on
    }

 

(4)authenticationManagerBean()

We covered configure (AuthenticationManagerBuilder auth), we use the implementation class DefaultPasswordEncoderAuthenticationManagerBuilder AuthenticationManagerBuilder to create their own implementation class InMemoryUserDetailsManager UserDetailsService and User by InMemoryUserDetailsManagerConfigurer, the system will default to us to create the implementation class DaoAuthenticationProvider AuthenticationProvider. However, we found that these objects are not Spring Bean. So we can override this method and is declared as a Bean, so that you can inject in the project and use of the Bean.

    @Bean(name = "myAuthenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

It can be seen through the source code of the parent class, in fact, when you call, have created a AuthenticationManager agent.

    public AuthenticationManager authenticationManagerBean() throws Exception {
        return new AuthenticationManagerDelegator(authenticationBuilder, context);
    }

 

(5)userDetailsServiceBean()

和(4)类似,Override this method to expose a UserDetailsService created from configure(AuthenticationManagerBuilder) as a bean. In general only thefollowing override should be done of this method:

    @Bean(name = "myUserDetailsService")
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

 

(6) UserDetailsService

 

Guess you like

Origin www.cnblogs.com/storml/p/10968797.html