Spring Security combat dry goods: the entrance of client OAuth2 authorization request

1. Preface

stay Spring Security combat dry goods: initial experience of OAuth2 third-party authorization In this article, I first talk about oauth2 Introduce some common concepts involved in OAuth2.0, and then directly let everyone feel OAuth2.0 through a DEMO 0 third party authorization function. Today, we will analyze the mechanism step by step.

2. Grasp the source


The above request URL is where we are Last The starting point for the third-party authentication operation of the client mentioned in the article. The default format is {baseUrl}/oauth2/authorization/{clientRegistrationId}, where clientRegistrationId represents a third-party identity and can be wechat, Alipay and other open platforms. Here is gitee. After the user clicks this request, he starts the authorization journey. If we all start from scratch, we must explore the mechanism step by step from this entrance. Spring Security must have intercepted / OAuth2 / authorization before enabling OAuth2 related processing logic. Then go and catch the source! Search from the source code! The IDEA shortcut key CTRL SHIFT R can be used to global search results.

As expected, I found three places. Write them down and look at them one by one!


Let's take a look at the first oauthauthorizationrequestredirectwebfilter, which implements the WebFilter interface of Spring Webflux. This is obviously something of Webflux. If you use Webflux, this will be useful, but it's not what we use now.


What's the second one? From the name, it looks like a default OAuth2 authorization request parser. Sometimes when the name is good, you know what this thing is about. I have to say that excellent framework details are well grasped. It implements the interface OAuth2AuthorizationRequestResolver:

public interface OAuth2AuthorizationRequestResolver {

    * Parse and encapsulate OAuth2AuthorizationRequest from HttpServletRequest object
   OAuth2AuthorizationRequest resolve(HttpServletRequest request);

    * Resolve and encapsulate OAuth2AuthorizationRequest from HttpServletRequest object and clientRegistrationId
   OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId);


That is, when we request / oauth2/authorization, the DefaultOAuth2AuthorizationRequestResolver will extract data from the HttpServletRequest corresponding to / oauth2/authorization and encapsulate it into the OAuth2AuthorizationRequest request object for further use.

Note: the default interception ID: / oauth2/authorization can also be customized.


Here is a brief mention that OAuth2AuthorizationRequest encapsulates some of the concept parameters related to OAuth2 described in the previous article. We will use it for the subsequent request class.

public final class OAuth2AuthorizationRequest implements Serializable {
    private static final long serialVersionUID = 520L;
    private String authorizationUri;
    private AuthorizationGrantType authorizationGrantType;
    private OAuth2AuthorizationResponseType responseType;
    private String clientId;
    private String redirectUri;
    private Set<String> scopes;
    private String state;
    private Map<String, Object> additionalParameters;
    private String authorizationRequestUri;
    private Map<String, Object> attributes;
    // Other methods are omitted


There's only one clue left. As soon as I saw that it inherited OncePerRequestFilter, I knew it must be him. Even its member variable contains the OAuth2AuthorizationRequestResolver used to resolve the OAuth2 request. Here we are on the right path. Let's start to analyze this filter. Here is its core filtering logic, which is the logic we want to know how OAuth2 authorization requests are intercepted and processed.

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   try {
      OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestResolver.resolve(request);
      if (authorizationRequest != null) {
         this.sendRedirectForAuthorization(request, response, authorizationRequest);
   } catch (Exception failed) {
      this.unsuccessfulRedirectForAuthorization(request, response, failed);

   try {
      filterChain.doFilter(request, response);
   } catch (IOException ex) {
      throw ex;
   } catch (Exception ex) {
      // Check to see if we need to handle ClientAuthorizationRequiredException
      Throwable[] causeChain = this.throwableAnalyzer.determineCauseChain(ex);
      ClientAuthorizationRequiredException authzEx = (ClientAuthorizationRequiredException) this.throwableAnalyzer
         .getFirstThrowableOfType(ClientAuthorizationRequiredException.class, causeChain);
      if (authzEx != null) {
         try {
            OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestResolver.resolve(request, authzEx.getClientRegistrationId());
            if (authorizationRequest == null) {
               throw authzEx;
            this.sendRedirectForAuthorization(request, response, authorizationRequest);
            this.requestCache.saveRequest(request, response);
         } catch (Exception failed) {
            this.unsuccessfulRedirectForAuthorization(request, response, failed);

      if (ex instanceof ServletException) {
         throw (ServletException) ex;
      } else if (ex instanceof RuntimeException) {
         throw (RuntimeException) ex;
      } else {
         throw new RuntimeException(ex);

The corresponding process of doFilterInternal is as follows:

The third part of this article is about how to analyze the redirection method based on spring redirection.

3. Summary

Today, we find the processing entry of OAuth2 authorization step by step from the source, and preliminarily analyze the functions of several key components and the interception logic of the core interceptor. In the follow-up, we will make clear the operation process step by step. Don't go away and lock: little fat man Yannong will learn Spring Security OAuth2 step by step.

Follow official account: Felordcn for more information

Personal blog: https://felord.cn

Posted by cirko on Sun, 08 May 2022 03:33:45 +0300