Record a solution to the problem of using SpringSecurity to integrate enterprise wechat scan logon – verification request source error in a micro service

Recently in the project meet a don’t pay attention to the problem at ordinary times, writing in a further tracking, late again in the near future in the project need to use the enterprise WeChat sweep login code, in the enterprise WeChat qr code embedded in the access to the page, the qr code loaded failure (check request source error), the results as shown in the figure below.

Scene: the repetition

Access the enterprise wechat QR code

  1. Add access whitelist to enterprise wechat management terminal;
  2. Set the trusted domain name on the enterprise wechat management terminal (the domain name must be the same as the enterprise wechat callback domain name)
  3. You must open the link to access the wechat QR code generated by the enterprise through the page jump

The implementation code

Login page (login.html) and jump links (ignore the ugly HTML layout, which is not beautified for the record)

<a href="https://testapi.xxxx.com/java/troy">Enterprise WeChat</a>
<p></p>
<a href="https://testapi.xxxx.com/java/troy1">Enterprise wechat 1</a>
<p></p>
Copy the code

Nginx configuration

 location /java/login {
    proxy_pass http://192.168.201.118:9999/java/login;
 }

 location /java/troy {
    proxy_pass http://192.168.201.118:9999/java/troy;
 }

 location /java/troy1 {
    proxy_pass http://192.168.201.118:9999/java/troy1;
 }
Copy the code

Springsecurity configuration in SpringBoot (other configurations omitted here)

@Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http.csrf().disable()
                .headers().hsts().disable().frameOptions().mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN)
                .contentSecurityPolicy("default-src https: data: 'unsafe-inline' 'unsafe-eval'")
                .and()// The default ReferrerPolicy is the referrerPolicy. NO_REFERRER policy
                .and()
                .cors().configurationSource(corsFilter())
Copy the code

controller

@Controller
public class LoginController {

    @GetMapping("/java/login")
    public String loginPage(Model model) {
        return "login"; }}@Slf4j
@Controller
public class TestController {

    @GetMapping("/java/troy")
    public String sso3(ServerWebExchange exchange) {
        log.info("come in /troy");
        String path = "redirect:https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=xxxxx&redirect_uri=https%3A%2F%2Ftestapi.xxxxx. com%2Fwxwork%2Fsso3-callback&state=073524&usertype=member";
        log.info("end /troy");
        returnpath; }}Copy the code

Operation process:

  1. First the browser opens the login address LoginController(“/ Java /login”)
  2. The login page login.html is displayed
  3. Click the page link to enter TestController(“/ Java/Troy “) to jump to the wechat API of the enterprise. Then, the wechat of the enterprise will be activated to generate a TWO-DIMENSIONAL code, and the page will display the user scanning code of the TWO-DIMENSIONAL code

Cast analysis problem

After failing to use SpringSecurity, some students in the project team called it through Go, and opened the qr code scanning page of the enterprise’s wechat using the same operation process. During this period, I searched some problems that the QR code could not be loaded with my colleagues on the Internet, but the available solutions were not found, and some points mentioned were too thick. Later, by comparing the jump link of Java and GO, it was found that there was no HTTP referer attribute when the link after the jump failed. Now that we’ve found the difference, it’s easy to take a look at the SpringSecurity framework’s handling of the referer and see if we can add it, so let’s get started.

Jump request comparison

When we perform step 3 in the operation flow through the login page, we can catch the request through the jump link to see the difference:

# failed requesthttps://aegis.qq.com/collect/pv?id=XfN&uin=&version=1.34.46&aid=xxxxx&platform=4&netType=4&sessionId=session-1198&from=h ttps://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=xxxx&redirect_uri=https%3A%2F%2Ftestapi.xxxx.com%2Fwxwork% 2Fsso3-callback&state=073524&usertype=member&referer=# successful requesthttps://aegis.qq.com/collect/pv?id=N&uin=&version=1.34.46&aid=xxxx&platform=4&netType=4&sessionId=session-10763&from=htt ps://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?appid=xxxx&redirect_uri=https%3A%2F%2Ftestapi.xxxx.com%2Fwxwork%2F sso3-callback&state=073524&usertype=member&referer=https%3A%2F%2Ftestapi.xxxx.com%2FCopy the code

By comparing the failed request, it is found that the referer parameter is missing. By searching the SpringSecurity documents and source code, SpringSecurity will add HTTP referer policy to the response header. The default HTTP referrer policy used by SpringSecurity is referrerPolicy.no_referrer. An introduction to HTTP referrer can be found at the link. So here the problem is simple to modify the SpringSecurity configuration, I used to configure the HTTP referrer policy referrerPolicy. ORIGIN, you can choose a reasonable setting according to your own project needs, here is a brief description of the meaning of these two policies, detailed explanation can see the link.

Referrerpolicy. NO_REFERRER: No – Referrer The whole head of the Referer is removed. Access source information is not sent with the request. (This explains why there is no referer value for failure);

Referrerpolicy. ORIGIN: ORIGIN only uses ORIGIN as a reference address at any time. For example, a page at www.troyqu.com/page.html will only use www.troyqu.com as a reference address.

To solve the problem

Added springsecurity configuration in the modified springboot referrerPolicy (ReferrerPolicyServerHttpHeadersWriter. ReferrerPolicy. ORIGIN)

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    http.csrf().disable()
            .headers().hsts().disable().frameOptions().mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN)
            .contentSecurityPolicy("default-src https: data: 'unsafe-inline' 'unsafe-eval'")
            .and().referrerPolicy(ReferrerPolicyServerHttpHeadersWriter.ReferrerPolicy.ORIGIN).and()// The default ReferrerPolicy is the referrerPolicy. NO_REFERRER policy
.and()
.cors().configurationSource(corsFilter())
Copy the code

After the restart of the service access found that the enterprise wechat TWO-DIMENSIONAL code can be opened, here all the problems have been completely solved.

Since SpringSecurity has set the HTTP referer, we can also compare it to see if the corresponding parameter is updated after the configuration is changed.

Console HTTP parameters configured by default

You can see that the referer policy in the response header has been updated to no-referrer.When the internal LoginController switches to the TestController interface, the request Header does not contain the referer parameter. Modified console HTTP parameters

You can see that the Referer policy in the Response header has been updated to originWhen the internal LoginController redirects to the TestController interface, the referer value in the Request header is the same as the origin value and does not contain any other HTTP path information.

conclusion

  1. Springsecurity uses referrerPolicy.no_referrer by default:no-referrerWhen we need to access the API of some other manufacturers and need to verify the referrer, the request will be invalid because the request lacks the referrer, resulting in the failure of the request processing.
  2. The HTTP referrer parameter has not been thoroughly understood before, and relevant knowledge needs to be supplemented later.