1. Introduction

Originally intended to Spring Security OAuth 2.0 mechanism after speaking, with small program login to practice, found that the small program login process and Spring Security OAuth 2.0 login process is a little different, I wrote a long time of things all overturned. But, but after a day, it suddenly feels ok again. Let’s try it together.

2. Analyze the small program login process

The login process for the applets looks like this:

OAuth 2.0 Code in Spring Security looks like this:

The biggest difference between these two figures is that the code obtained in wechat applets does not need to be called by the backend server, whereas Spring Security does (step 1, Step 2, step 3). Tencent probably borrowed OAuth 2.0 as well, but with some changes.

That’s the difference that makes me give up. Can anyone think of a solution?

If the applet already holds the code, it still needs to pass the code to the back-end server to execute the subsequent process. So can we use the third step in Figure 2 to call redirectUri? Another way to look at it is that the third party is the applet which is passing a code to the back end server anyway, so it just returns the login status, and the rest of the login process is independent of the applet. I think it’s ok. In Spring Security we can use code to exchange tokens via tokenUri. Therefore, in the wechat mini program login process, code only exchanges the login status, without specific requirements. However, the back end definitely needs to obtain some user information, such as openId, user wechat information and so on. In short, it should be implemented according to the API provided by wechat platform. This can be done by adapting tokenUri and userInfoUri.

3. Use for reference

All of the assumptions were correct and I implemented them, but the transformation cost was too high and a lot of compatibility code was written that was difficult to implement and understand without going deep into Spring Security.

To simplify the implementation, I decided to borrow the ideas of OAuth 2.0 from Spring Security. Filter intercepts the login URL of the applet, and then executes the RestTemplate command to obtain the result from the wechat server. After processing, the user returns to the login state. The sequence diagram is as follows:

Corresponding pseudo-code implementation:

package cn.felord.spring.security.filter;

import org.springframework.http.ResponseEntity;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;

/** * Applets login filter **@author felord.cn
 * @since1.0.4. RELEASE * /
public class WeChatAppLoginFilter extends OncePerRequestFilter {

    private final RequestMatcher requiresAuthenticationRequestMatcher;
    private final RestTemplate restTemplate;
    private String appId;
    private String secret;
    private static final String WX_URL = "https://api.weixin.qq.com/sns/jscode2session";

    public WeChatAppLoginFilter(String loginProcessingUrl, String appId, String secret) {
        this.appId = appId;
        this.secret = secret;
        Assert.notNull(loginProcessingUrl, "loginProcessingUrl must not be null");
        this.requiresAuthenticationRequestMatcher = new AntPathRequestMatcher(loginProcessingUrl, "POST");
        this.restTemplate = new RestTemplate();
    }

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

        // Block wechat login
        if (requiresAuthenticationRequestMatcher.matches(request)) {
            // Todo takes the code argument from the request
            String jsCode = "You implement it yourself from the request.";
            // Todo necessary validation write yourself
            MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
            queryParams.add("appid".this.appId);
            queryParams.add("secret".this.secret);
            queryParams.add("js_code", jsCode);
            queryParams.add("grant_type"."authorization_code");


            URI uri = UriComponentsBuilder.fromHttpUrl(WX_URL)
                    .queryParams(queryParams)
                    .build()
                    .toUri();
            //todo where Object encapsulates itself as a concrete Object
            ResponseEntity<Object> result = this.restTemplate.getForEntity(uri, Object.class);

            // Todo handles business logic such as back-end storage, back-end authorization, role resource handling, registration, session_key handling, etc
            // Finally put it in HttpServletResponse to return the front-end return

        } else{ filterChain.doFilter(request, response); }}}Copy the code

Finally, don’t forget to put the filter configuration to WebSecurityConfigurerAdapter HttpSecurity.

4. To summarize

This article explains the thinking process of combining Spring Security and wechat applet login. There is no need to write a long article on OAuth 2.0. The reason for writing it is to let you know that you should be good at finding some similar things in development, and explore the possibility of their combination through comparison of differences, which is also a way to improve yourself. The method is more important than the result, and you can be creative by developing your own methodology. I am: code farmers xiao Pangge, pay more attention to share more original programming dry goods.

Follow our public id: Felordcn for more information

Personal blog: https://felord.cn