Permission management is a necessary function of each project, but the complexity of their requirements varies. Simple projects may be solved by a Filter or Interceptor, while more complex projects may introduce Security frameworks, such as Shiro and Spring Security. Among them, Spring Security is criticized for its complexity and complexity due to the excessive processes and classes involved. But Spring Security isn’t as complicated as it sounds if you can tease out the key components and key classes. This article provides an in-depth analysis of Spring Security’s authentication and authorization mechanisms in combination with the scaffolding framework’s permission management implementation (Jboost-Auth module, source code available at the end of the article).

Use Spring Security for authentication and authentication

Spring Security mainly implements Authentication (Who are you?) What can you do?

Authentication (login) process

The Spring Security authentication process and the main categories involved are shown in the following figure.

There are UsernamePasswordAuthenticationFilter to implement authentication entry for AbstractAuthenticationProcessingFilter, general

  1. Filter parse request parameters, the client sends the user name, password, and other packaging for Authentication, the Authentication have UsernamePasswordAuthenticationToken general implementation
  2. Filter that calls the AuthenticationManagerauthenticate()Method authenticates Authentication, and the default implementation of AuthenticationManager is ProviderManager
  3. When ProviderManager authenticates, it delegates to a list of AuthenticationProviders and calls the AuthenticationProvider’s in the listauthenticate()Method. If either of the AuthenticationProvider methods passes, the authentication succeeds. Otherwise, an AuthenticationException exception is thrownsupports()Method to determine whether the Provider authenticates the current type of Authentication.
  4. After the completion of the certification, the filter by AuthenticationSuccessHandler (success) or AuthenticationFailureHandler (fail) to the result of the certification process, such as return to token or authentication error

Key classes involved in authentication

  1. UsernamePasswordAuthenticationFilter login authentication entry

In the project RestAuthenticationFilter inherited UsernamePasswordAuthenticationFilter, UsernamePasswordAuthenticationFilter encapsulation for UsernamePasswordAuthenticationToken submitted by the client parameters, for the AuthenticationManager for certification.

RestAuthenticationFilter fu wrote UsernamePasswordAuthenticationFilter attemptAuthentication logic (request, response) method, According to the value of loginType to login parameters wrapped in Authentication, the Authentication information (loginType is when the USER is UsernameAuthenticationToken, If loginType is Phone, PhoneAuthenticationToken is used for authentication by the downstream AuthenticationManager.

  1. Authentication Information

Use the realization of Authentication to store Authentication information, generally for UsernamePasswordAuthenticationToken, including

  • Principal: The principal of identity, usually a user name or mobile phone number
  • Credentials: Credentials, usually passwords or mobile verification codes
  • Authorities: Information about the authority, usually the Role
  • IsAuthenticated: Indicates whether authenticated

Authentication implementation in this project:

  • UsernameAuthenticationToken: use the user name login Authentication of encapsulation

    • principal => username
    • credentials => password
    • Extended two properties: uuid, code, to verify the graphic captcha
  • PhoneAuthenticationToken: Authentication encapsulated when a mobile phone Authentication code is used for login

    • Principal => phone
    • The credentials => code

Both inherited UsernamePasswordAuthenticationToken.

  1. AuthenticationManager AuthenticationManager

The AuthenticationManager interface contains a authenticate(authentication) method. ProviderManager is the implementation of AuthenticationManager and manages a list of AuthenticationProviders (concrete authentication logical providers). In its authenticate(Authentication) method, each AuthenticationProvider in the AuthenticationProvider list is called with its supports(Class
authentication) to determine whether to use the Provider to authenticate authentication. If applicable, authenticate(Authentication) of the AuthenticationProvider is called to complete authentication. If either AuthenticationProvider completes authentication, the authentication is returned.

  1. AuthenticationProvider AuthenticationProvider

3 You can see that the actual authentication logic is provided by AuthenticationProvider

  • UsernameAuthenticationProvider: support for certification UsernameAuthenticationToken types of authentication information. At the same time use PasswordRetryUserDetailsChecker to users on the number of wrong password more than 5 times, limit the login operation in 10 minutes
  • PhoneAuthenticationProvider: support for certification PhoneAuthenticationToken types of authentication information

Both inherited DaoAuthenticationProvider – through UserDetailsService loadUserByUsername (String username) saved user information populated UserDetails, Again with the client to submit the Authentication information Authentication comparison (e.g., compares with UsernameAuthenticationToken password), to complete the certification.

  1. Obtaining user information UserDetailsService

The UserDetailsService provides the loadUserByUsername(username) method to obtain the saved user information (for example, the user account information saved in the database).

The UserDetailsService implementation of this project includes

  • UsernameUserDetailsService: through the information retrieved from the database account user name
  • PhoneUserDetailsService: Obtains account information from the database by mobile phone number
  1. Authentication Result processing

Authentication is successful, call AuthenticationSuccessHandler onAuthenticationSuccess (request, response, authentication) method, This is set when RestAuthenticationFilter is injected into SecurityConfiguration. After successful authentication in this project, the JWT token is generated and returned to the client.

Authentication failed (account checking in the process of failure or throw an exception), call AuthenticationFailureHandler onAuthenticationFailure (request, response, the exception) method, The RestAuthenticationFilter was set when it was injected into the SecurityConfiguration and an error message was returned.

Most of the above key classes and their associations are configured in SecurityConfiguration.

  1. Utility class

SecurityContextHolder is the container for the SecurityContext. By default, ThreadLocal is used to store the SecurityContext, making it accessible to all methods of the same thread. The SecurityContext stores the principal information of the application, which is represented by Authentication in Spring Security. In AbstractAuthenticationProcessingFilter, after the success of the certification, Call the successfulAuthentication() method to save Authentication using the SecurityContextHolder, And call the AuthenticationSuccessHandler to complete the follow-up work (such as returned token, etc.).

Example of using SecurityContextHolder to retrieve user information:

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
    String username = ((UserDetails)principal).getUsername();
} else {
    String username = principal.toString();
}
Copy the code

Authentication process

Spring Security has two implementation mechanisms for authentication (authorization) :

  • FilterSecurityInterceptor: through the Filter of HTTP resources access authentication
  • MethodSecurityInterceptor: through AOP for authentication method is called. In GlobalMethodSecurityConfiguration injection,

Need to add annotations on configuration class @ EnableGlobalMethodSecurity (prePostEnabled = true) make GlobalMethodSecurityConfiguration configuration take effect.

The authentication process and main categories involved are as follows:

  1. After the login is complete, the token is generally returned for the next invocation for identity Authentication, generating Authentication
  2. FilterSecurityInterceptor interceptors through FilterInvocationSecurityMetadataSource obtain access to the current resource needs
  3. FilterSecurityInterceptor calls the AccessDecisionManager authentication manager decide method of authentication
  4. The AccessDecisionManager votes on the authentication of the AccessDecisionVoter list. If the voter does not pass the authentication, it throws an AccessDeniedException exception
  5. Similar to FilterSecurityInterceptor MethodSecurityInterceptor process

Key classes involved in authentication

  1. The authentication information extracts RestAuthorizationFilter

For the front and back separated projects, after the login is complete, we generally access the interface through the token returned during the login.

Before the Authentication starts, we need to verify the token, and then generate the Authentication information Authentication to the downstream for Authentication (authorization).

RestAuthorizationFilter parses the JWT token reported by the client, obtains the UserDetails, and verifies the validity of the token. And generate the Authentication (UsernamePasswordAuthenticationToken), for the use of downstream through SecurityContextHolder deposit SecurityContext.

  1. AbstractSecurityInterceptor authentication entry

Three implementations:

  • FilterSecurityInterceptor: the authentication based on the Filter implementation, on the Http interface level. FilterSecurityInterceptor from SecurityMetadataSource implementation DefaultFilterInvocationSecurityMetadataSource to obtain the required permissions to access the resources The AccessDecisionManager is then called to vote on the authorization decision. If the vote passes, access to the resource is allowed, otherwise access is denied.
  • MethodSecurityInterceptor: the authentication based on AOP implementation, on the method of hierarchy.
  • AspectJMethodSecurityInterceptor: used to support the AspectJ JointPoint MethodSecurityInterceptor
  1. Gets resource permission information SecurityMetadataSource

SecurityMetadataSource Reads the permissions required to access the resource. The read is the configured access rule, such as the one we configured in the configuration class:

@Override
protected void configure(HttpSecurity http) throws Exception{
    http.authorizeRequests()
        .antMatchers(excludes).anonymous()
        .antMatchers("/api1").hasAuthority("permission1")
        .antMatchers("/api2").hasAuthority("permission2")... }Copy the code

You can customize a SecurityMetadataSource to get resource permission rule information from a database or other store.

  1. Authentication Manager AccessDecisionManager

The Decide (Authentication, Object, configAttributes) method of the AccessDecisionManager interface authenticates this request

  • Authentication: Indicates the authentication information of the request, including the authority (such as role) information
  • Object: the currently invoked protected object, such as an interface
  • ConfigAttributes: configuration attributes associated with the protected object, indicating the conditions that must be met to access the protected object, such as roles

Implementers of the AccessDecisionManager interface are authenticated by calling their internal List

> The vote(Authentication, Object, Attributes) method for each element in the list, which is divided into the following three implementations according to the decision
>

  • AffirmativeBased: the one-vote affirmative policy. As long as an AccessDecisionVoter passes (AccessDecisionVoter.voteAccessDecisionVoter. ACCESS_GRANTED) is returned, and the authentication succeeds. For default implementation
  • Consensus-based: The minority follows the majority strategy. Most AccessDecisionVoter through, the authentication through, if equal vote and vote, depending on the value of the variable allowIfEqualGrantedDeniedDecisions to decide, this value defaults to true
  • 14. Thursday, however ous-based: a strategy for passing unanimity. All AccessDecisionVoter pass or abstain (return AccessDecisionVoter. ACCESS_ABSTAIN). All AccessDecisionVoter pass or abstain (return AccessDecisionVoter. If full waiver, the decision, according to the value of the variable allowIfAllAbstainDecisions this value to false by default
  1. Authenticated voter AccessDecisionVoter

Similar to AuthenticationProvider, AccessDecisionVoter also includes the supports(attribute) method (whether this Voter is used to authenticate requests) and the vote (authentication, object, Attributes) method (specific authentication voting logic)

The AccessDecisionManager of FilterSecurityInterceptor Voter lists (AbstractInterceptUrlConfigurer createFilterSecurityInterceptor () set in the) include:

  • WebExpressionVoter: verifies authenticated Authentication.

The list of voters in the AccessDecisionManager MethodSecurityInterceptor (GlobalMethodSecurityConfiguration. The AccessDecisionManager () The Settings include:

  • PreInvocationAuthorizationAdviceVoter: If @ EnableGlobalMethodSecurity annotations opens the prePostEnabled, then add the Voter, using the @ PreAuthorize annotation method for authentication
  • Jsr250Voter: if @ EnableGlobalMethodSecurity annotations opens the jsr250Enabled, then add the Voter, method of @ Secured annotations to vote
  • RoleVoter: Always add ifConfigAttribute.getAttribute()ROLE_If yes, participate in the authentication vote
  • AuthenticatedVoter: Always add ifConfigAttribute.getAttribute()A value ofIS_AUTHENTICATED_FULLY.IS_AUTHENTICATED_REMEMBERED.IS_AUTHENTICATED_ANONYMOUSLYOne of them participates in the authentication vote
  1. Authentication result processing

ExceptionTranslationFilter exception handling Filter, the exception thrown in the process of certification authentication process, including:

  • AuthenticationEntryPoint: Throws AuthenticationException or AccessDeniedException to the filter chain but Authentication is

The situation of the AnonymousAuthenticationToken for processing. Token validation failure, such as incorrect or outdated token, then through ExceptionTranslationFilter AuthenticationEntryPoint for processing, This project USES RestAuthenticationEntryPoint to return the unified format of the error message

  • AccessDeniedHandler: Throw in the filter chain AccessDeniedException but without Authentication for AnonymousAuthenticationToken for processing, This project uses RestAccessDeniedHandler to return error messages in a uniform format

If it is a sell AccessDeniedException MethodSecurityInterceptor jian power, and through the @ RestControllerAdvice provides a unified exception handling, will be handled by unified exception handling class, Because MethodSecurityInterceptor is AOP mechanism, can be made of @ RestControllerAdvice capture.

In this project, RestAuthorizationFilter is located in the front of ExceptionTranslationFilter in the Filter chain, so that the exception thrown cannot been ExceptionTranslationFilter capture, By cn. Jboost. Base. The starter. Web. ExceptionHandlerFilter capture process.

Can also be RestAuthorizationFilter into ExceptionTranslationFilter, But need to be in the RestAuthorizationFilter SecurityContextHolder. GetContext () getAuthentication AnonymousAuthenticationToken () Judgment, because AnonymousAuthenticationFilter located at the front ExceptionTranslationFilter, Will generate a AnonymousAuthenticationToken to a request for Authentication is empty, in the SecurityContext.

conclusion

A security framework generally consists of authentication and authorization. Authentication determines who you are, that is, whether you have a legitimate access identity, and authorization determines whether you have permission to access corresponding resources. Spring Security uses Filter for authentication and a Filter (interface level) + AOP (method level) approach for authorization. This paper is relatively partial to the theory, but also combined with the implementation of scaffolding, control view, should be easier to understand.

This article is based on the Spring Boot scaffolding in the permission management module, the scaffolding provides a separation of the front and back end of the permission management implementation, the effect is as follows, you can pay attention to the author’s public number “halfway Rain song”, reply “jBoost” to obtain the source address.


[reprint please note the source] Yu Ge, you can pay attention to the author’s public account: Halfway Yu Ge