spring security Customization Guide

sequence

In this paper, several ways to customize the look of spring security

Main way

  • Custom UserDetailsService
  • Custom passwordEncoder
  • Custom filter
  • Custom AuthenticationProvider
  • Custom AccessDecisionManager
  • Custom securityMetadataSource
  • Custom access control access
  • Custom authenticationEntryPoint
  • Customize more WebSecurityConfigurerAdapter

Custom UserDetailsService

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //......
    @Bean
    @Override
    protected UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("demoUser1").password("123456")
                .authorities("ROLE_USER","read_x").build());
        manager.createUser(User.withUsername("admin").password("123456")
                .authorities("ROLE_ADMIN").build());
        return manager;
    }
}
By rewriting userDetailsService () method custom userDetailsService. Shown here is InMemoryUserDetailsManager.
spring security built JdbcUserDetailsManager, you can expand their own

Custom passwordEncoder

Since encryption password defined, the following examples
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //......

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService);
        authProvider.setPasswordEncoder(encoder());
        return authProvider;
    }

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder(11);
    }
}

Custom filter

Custom filter can not do without a built-in filter cognitive order for spring security:

Standard Filter Aliases and Ordering

Various spring security filter built in the following order:

Alias Filter Class Namespace Element or Attribute
CHANNEL_FILTER ChannelProcessingFilter http/intercept-url@requires-channel
SECURITY_CONTEXT_FILTER SecurityContextPersistenceFilter http
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter session-management/concurrency-control
HEADERS_FILTER HeaderWriterFilter http/headers
CSRF_FILTER CsrfFilter http/csrf
LOGOUT_FILTER LogoutFilter http/logout
X509_FILTER X509AuthenticationFilter http/x509
PRE_AUTH_FILTER AbstractPreAuthenticatedProcessingFilter Subclasses N/A
CAS_FILTER CasAuthenticationFilter N/A
FORM_LOGIN_FILTER UsernamePasswordAuthenticationFilter http/form-login
BASIC_AUTH_FILTER BasicAuthenticationFilter http/http-basic
SERVLET_API_SUPPORT_FILTER SecurityContextHolderAwareRequestFilter http/@servlet-api-provision
JAAS_API_SUPPORT_FILTER JaasApiIntegrationFilter http/@jaas-api-provision
REMEMBER_ME_FILTER RememberMeAuthenticationFilter http/remember-me
ANONYMOUS_FILTER AnonymousAuthenticationFilter http/anonymous
SESSION_MANAGEMENT_FILTER SessionManagementFilter session-management
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter http
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor http
SWITCH_USER_FILTER SwitchUserFilter N/A

Built-in authentication filter

  • UsernamePasswordAuthenticationFilter
Parameters username, password, and take UsernamePasswordAuthenticationFilter, parameter extraction structure UsernamePasswordAuthenticationToken authentication, then fill SecurityContextHolder success of Authentication
  • BasicAuthenticationFilter
header inside there Authorization, and value begins with Basic, then go BasicAuthenticationFilter, parameter extraction structure UsernamePasswordAuthenticationToken authentication, then fill SecurityContextHolder success of Authentication
  • AnonymousAuthenticationFilter
The user is not logged in, to fill AnonymousAuthenticationToken SecurityContextHolder of Authentication

Define your own filter

You can inherit GenericFilterBean like UsernamePasswordAuthenticationFilter or AnonymousAuthenticationFilter, or, as BasicAuthenticationFilter inherited OncePerRequestFilter.
About GenericFilterBean difference with OncePerRequestFilter can see this in the spring mvc several types of interceptors contrast

Custom filter to complete the main functions are as follows:

  • Extracting authentication parameters
  • Call authentication, success is filled SecurityContextHolder of Authentication, failure exception is thrown

Examples

public class DemoAuthFilter extends GenericFilterBean {

    private final AuthenticationManager authenticationManager;

    public DemoAuthFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        String token = httpServletRequest.getHeader("app_token");
        if(StringUtils.isEmpty(token)){
            httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "invalid token");
            return ;
        }

        try {
            Authentication auth = authenticationManager.authenticate(new WebToken(token));
            SecurityContextHolder.getContext().setAuthentication(auth);
            filterChain.doFilter(servletRequest, servletResponse);
        } catch (AuthenticationException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
        }
    }
}

Set filter order

After completion of the above defined filter, then it must be placed into the filterChain
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //......
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(new DemoAuthFilter(authenticationManager()), BasicAuthenticationFilter.class);
        http.csrf().disable();
        http.logout().disable();
        http.sessionManagement().disable();
    }
}
Here he added before BasicAuthenticationFilter, of course, can be replaced according to the situation directly UsernamePasswordAuthenticationFilter
http.addFilterAt(new DemoAuthFilter(authenticationManager()),UsernamePasswordAuthenticationFilter.class);

Custom AuthenticationProvider

AuthenticationManager interfaces have achieved the equivalent of a ProviderManager provider chain, inside which there is a List <AuthenticationProvider> providers, to achieve authentication provider.

public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        Class<? extends Authentication> toTest = authentication.getClass();
        AuthenticationException lastException = null;
        Authentication result = null;
        boolean debug = logger.isDebugEnabled();

        for (AuthenticationProvider provider : getProviders()) {
            if (!provider.supports(toTest)) {
                continue;
            }

            //......
            try {
                result = provider.authenticate(authentication);

                if (result != null) {
                    copyDetails(authentication, result);
                    break;
                }
            }
            catch (AccountStatusException e) {
                prepareException(e, authentication);
                // SEC-546: Avoid polling additional providers if auth failure is due to
                // invalid account status
                throw e;
            }
            catch (InternalAuthenticationServiceException e) {
                prepareException(e, authentication);
                throw e;
            }
            catch (AuthenticationException e) {
                lastException = e;
            }
        }

        //......
    }
AuthenticationProvider by supports methods to identify whether it can handle this type of Authentication.
AnonymousAuthenticationFilter configuration is AnonymousAuthenticationToken, processed by AnonymousAuthenticationProvider
public class AnonymousAuthenticationProvider implements AuthenticationProvider,
        MessageSourceAware {
        //......
        public boolean supports(Class<?> authentication) {
            return (AnonymousAuthenticationToken.class.isAssignableFrom(authentication));
        }
}        
UsernamePasswordAuthenticationFilter, BasicAuthenticationFilter configuration is UsernamePasswordAuthenticationToken, of the DaoAuthenticationProvider (parent class AbstractUserDetailsAuthenticationProvider) treated
public abstract class AbstractUserDetailsAuthenticationProvider implements
        AuthenticationProvider, InitializingBean, MessageSourceAware {
        //......
        public boolean supports(Class<?> authentication) {
            return (UsernamePasswordAuthenticationToken.class
                .isAssignableFrom(authentication));
        }
}            

We like the above customized WebToken, examples of which are:

Authentication can implement an interface, or inherit AbstractAuthenticationToken
public class WebToken extends AbstractAuthenticationToken {

    private final String token;

    public WebToken(String token) {
        super(null);
        this.token = token;
    }

    @Override
    public Object getCredentials() {
        return this.token;
    }

    @Override
    public Object getPrincipal() {
        return null;
    }
}

Here it is a custom look to support such WebToken of AuthenticationProvider

AuthenticationProvider to achieve the function according to the parameters to verify that you can log on through, not through an exception is thrown; it is acquired by the authentication GrantedAuthority fill in
if it is inherited AbstractAuthenticationToken, is filling its authorities attribute
the previous custom DemoAuthFilter will after successful login, the authentication is written to the context in SecurityContextHolder
can be achieved AuthenticationProvider interface, or inherited AbstractUserDetailsAuthenticationProvider ( 默认集成了preAuthenticationChecks以及postAuthenticationChecks )
@Service
public class MyAuthProvider implements AuthenticationProvider {
    //...
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        //......
    }
    @Override
    public boolean supports(Class<?> authenticationClass) {
        return return (WebToken.class
                .isAssignableFrom(authenticationClass));
    }
}

Custom AccessDecisionManager

Front filter processing login problems, then specify whether the resource can be accessed by the FilterSecurityInterceptor problem to deal with. The FilterSecurityInterceptor is used to authenticate the AccessDecisionManager.

Several AccessDecisionManager implementation:

  • AffirmativeBased(spring security默认使用)
As long as there is cast by (ACCESS_GRANTED) votes, directly ruled by. If you do not vote by vote and the opposition (ACCESS_DENIED) ticket in one and above, not directly ruled by.
  • ConsensusBased(少数服从多数)
By the number of votes is greater than the penalty for the votes against by; by votes is less than the penalty for the votes against not pass; by votes equal votes for and against, can be performed by determining whether a configuration allowIfEqualGrantedDeniedDecisions (the default is true).
  • UnanimousBased(反对票优先)
No matter how many voters voted by how much (ACCESS_GRANTED) ticket, as long as there against (ACCESS_DENIED), that it is not ruled by; and if there is no negative vote cast by voters vote, then ruled by.

Examples

One of its self-defined and can refer to talk about the role hierarchy spring security , showing how to customize AccessDecisionVoter.

Custom securityMetadataSource

Mainly achieved by custom ObjectPostProcessor, specific examples refer spring security permissions dynamic configuration url

Custom access control access

AuthorizeRequests control can be used permitAll, anonymous, authenticated, hasAuthority, hasRole etc.

                .antMatchers("/login","/css/**", "/js/**","/fonts/**","/file/**").permitAll()
                .antMatchers("/anonymous*").anonymous()
                .antMatchers("/session").authenticated()
                .antMatchers("/login/impersonate").hasAuthority("ROLE_ADMIN")
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/auth/*").hasAnyRole("ADMIN","USER")
These are built using the spring security of expression. Like hasAuthority, etc., they still achieved using internal access methods. So we can directly access, to achieve maximum customization.

Examples

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/login/**","/logout/**")
                .permitAll()
                .anyRequest().access("@authService.canAccess(request,authentication)");
    }
}

This is a bit like using a spring EL expressions to achieve the following examples

@Component
public class AuthService {

    public boolean canAccess(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if(principal == null){
            return false;
        }

        if(authentication instanceof AnonymousAuthenticationToken){
            //check if this uri can be access by anonymous
            //return
        }

        Set<String> roles = authentication.getAuthorities()
                .stream()
                .map(e -> e.getAuthority())
                .collect(Collectors.toSet());
        String uri = request.getRequestURI();
        //check this uri can be access by this role

        return true;

    }
}

Custom authenticationEntryPoint

For example, you want to change the basic certification realmName, in addition to further specify the spring security configuration

security.basic.realm=myrealm

It can be so

    httpBasic().authenticationEntryPoint(createBasicAuthEntryPoint("myrealm"))

    public static BasicAuthenticationEntryPoint createBasicAuthEntryPoint(String realmName){
        BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
        entryPoint.setRealmName(realmName);
        return entryPoint;
    }

Customize more WebSecurityConfigurerAdapter

spring security does not support the use of antMatchers not, so you can customize many WebSecurityConfigurerAdapter, priority use order to achieve matching of coverage, specifically refer to this article Multiple Entry Points in Spring Security

summary

There are other ways to customize, and other follow-up have found supplemented on.

doc

Original Address: https: //segmentfault.com/a/1190000012560773

Guess you like

Origin www.cnblogs.com/jpfss/p/11022057.html