Research on how to handle 302 on the front end and set third-party cookies

Research on how to handle 302 on the front end and set third-party cookies

1. How to solve the backend 302 redirection problem

Background: If the certification center gateway detects that the user is not logged in, it will redirect the user to the login page of the certification center.

​ At this time, if the Oauth2 protocol is used, after successful login, the front end needs to access the /Oauth2/1/authorize interface with the successful login information (jwt). At this time, the interface will redirect back to the redirect_uri address. At this time The focus is on how to access the /Oauth2/1/authorize interface .

Let’s list several request methods:

  1. Ajax
  2. Fetch
  3. Location.href
  4. Form form
  5. Nvigator.sendBeacon
technology Features it's usable or not
Ajax(XMLHttpRequest Without reloading the entire page, you can exchange data with the server and update part of the web page content. The 302 status code cannot be captured, and if the path returned by the Location of the backend response header is inconsistent with the Ajax Referer, a cross-domain error will occur. . ×
Fetch For the case of 302, fetch actually has a special configuration called redirect, which can capture part of the content of 302. But it is a pity that the content of the current response is very limited. It can only capture whether there is a 302 when accessing the interface. It cannot capture the specific jump path of 302, and it cannot follow the jump. ×
Location.href The browser address directly jumps to the interface, and the Get request is used by default. There is no cross-domain problem. The browser can also directly follow the 302 redirect generated by the backend.
Form form To make an access request by refreshing the entire page, you can use the Get/Post method, or you can follow the 302 jump performed by the backend. The disadvantage is that you need to create a new form and the operation is more complicated.
Nvigator.sendBeacon navigator.sendBeacon()Method can be used to asynchronously transfer small amounts of data to a web server via HTTP POST . At the same time, it avoids some problems of sending analysis data using traditional technologies (such as: ). The disadvantage is that it only supports POST requests, is an asynchronous operation, and does not follow backend 302.XMLHttpRequest

Do a test based on the above method:

We make a 302 redirect interface. The redirect paths are http://localhost:3000/login and https://www.baidu.com. The client's domain name is localhost. The situation is as follows:

Insert image description here

If you use commonly used Ajax, such as Axios or Fetch, the front-end code and effects are as follows:

1. Axios: When the button is clicked, the /redirectTo interface is called, and the backend returns a 302 redirect. At this time, we can see that the redirected address does not jump on the browser as expected, but re-uses the XHR request. The address after redirection. At this time, because the Referer of the interface request header is localhost:3000 and RequestURL: https:www.baidu.com, there is a cross-domain problem, so an error is reported.

Insert image description here
Insert image description here
Insert image description here

  • What if the redirected address returned by the backend does not have a cross-domain problem (it is the same domain as the client at this time)?

Although there is no cross-domain problem at this time, the redirected address is accessed using XHR, but your client does not have Servlet and other services enabled, so the interface will return 404NotFound.
Insert image description here
Insert image description here
Insert image description here

  • To sum up, using Ajax to handle 302 will not work.

2. Use Fetch. There are different opinions on fetch on the Internet. After testing, fetch cannot follow the 302 jump page and will return the message body after the request.

Insert image description here
Insert image description here
Insert image description here

3. Using Location.href, the redirection can be successful regardless of whether the redirected address is cross-domain.

Insert image description here
Insert image description here
Insert image description here

4. Using a form to make a 302 jump can also be successful, but it requires creating a virtual node, which is more complicated to handle.

Insert image description here
Insert image description here
Insert image description here

5. Nvigator.sendBeacon, since this method must use Post, change the backend code. Although there is no cross-domain problem using this method, because it is an asynchronous method, the browser will not follow the 302 operation.

Insert image description here
Insert image description here
Insert image description here

Summary: Use Location.href to directly access the interface

​ Among the above five methods, Ajax and Fetch are both asynchronous requests and cannot follow the browser 302 operation, and the Location and other information returned by the interface cannot be obtained, so they are not used. The Form form can be used and its functions are relatively comprehensive, but the implementation method is relatively complicated, and the Form form is usually used for form content submission, which is inconsistent with the scene semantics, so Pass**. The Location.href method is to directly use the browser to access the interface with a Get request. The parameters are easy to carry and can also follow the redirect operation, so it is adopted. **

Attached is the code:

import serviceInstance from "../../services";

// const res = serviceInstance({
    
    
//   url: "/redirectTo", //不用引入,直接在api后面接接口
//   method: "get",
//   data: {},
// });
// console.log(res);
function Home() {
    
    
  const setRedirect = () => {
    
    
    const res = serviceInstance({
    
    
      url: "/redirectTo", //不用引入,直接在api后面接接口
      method: "get",
      data: {
    
    },
    });
    console.log(res);
  };

  const useFetchSetRedirect = () => {
    
    
    const res = fetch("/redirectTo",{
    
    
      method: "get",
      redirect:'follow'
    });
    console.log(res);
  };

  const useLocationRedirect = () => {
    
    
    window.location.href = "http://localhost:8080/redirectTo"
  };
  const useFormData = ()=>{
    
    
    const form = document.createElement("form");
    form.action = "http://localhost:8080/redirectTo";
    document.getElementById("container").appendChild(form);
    form.submit();
    document.getElementById("container").removeChild(form);
  }
  const useSendBeacon = ()=>{
    
    
    navigator.sendBeacon("http://localhost:8080/redirectToPost")
  }
  return (
    <div id="container">
      <button onClick={
    
    setRedirect}>测试Axios重定向</button>
      <button onClick={
    
    useFetchSetRedirect}>测试Fetch重定向</button>
      <button onClick={
    
    useLocationRedirect}>测试location重定向</button>
      <button onClick={
    
    useFormData}>测试Form表单重定向</button>
      <button onClick={
    
    useSendBeacon}>测试SendBeacon重定向</button>
    </div>
  );
}

export default Home;

package com.xuan.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
public class TestController {
    
    
    @GetMapping("/redirectTo")
    void testRedirect(HttpServletResponse response) throws IOException {
    
    
        String testUrl = "https://www.baidu.com";
//        String testUrl2 = "http://localhost:3000/login";
        response.sendRedirect(testUrl);
    }

    @PostMapping ("/redirectToPost")
    void testRedirectPost(HttpServletResponse response) throws IOException {
    
    
        String testUrl = "https://www.baidu.com";
//        String testUrl2 = "http://localhost:3000/login";
        response.sendRedirect(testUrl);
    }
}

2. How do subsystems (systems connected to the certification center) access the certification center and obtain login status?

Background: Since the subsystem and the certification center are different systems, how to know the logged-in status during the process of redirecting back to the subsystem after the certification center successfully logs in?

​ At this time, during the redirection process, we need to pass information to other systems. There are only three ways (as far as I know):

  1. ​Browser address bar carry

  2. ​ Cookie

  3. ​ Window.postMessage

    Method to realize Features it's usable or not
    Browser address bar carry Advantages: Easy to operate, no restrictions on the same domain; Disadvantages: Information is completely exposed in the address bar, and security is not high
    Cookie Advantages: When setting cookies, you can set cookies on the application that needs to be obtained through Domain, Path, SameSite and other fields, which is more secure and accurate; Disadvantages: Following the same origin restriction of the browser, the cookies set are only in Share under this domain name or subdomain name.
    Window.postMessage It is a cross-domain information transmission method provided by the browser. After completing the login operation at the authentication center, if you get the Token, you can use this method to transmit information. However, it does not match the usage scenario, so Pass it. ×

Summary: Both the browser address bar and cookies can complete the operation of transmitting information (assess-token or code) after 302. Each has its own advantages and disadvantages, and different methods should be adopted according to project needs and specific circumstances. It is recommended to use cookies in the same domain, and it is recommended to use the browser address bar to carry them in different domains.

  • The subsystem is in the same domain as the certification center

    ​Using the Cookie method can achieve single sign-on relatively simply, setting the Cookie (access-token) to a specific domain (Domain), and restricting the corresponding system through Path, so that the authentication center can achieve the effect of single sign-on. However, the browser must turn on cookies and set specific conditions for cookies to prevent other systems from obtaining user information through CSRF and other means.

  • Cross-domain subsystem and certification center

​ It is recommended to use the browser address bar to carry the information. Considering security issues at this time, the access-token should not be placed in the address bar in plain text. Instead, the code carried after redirection should be transmitted back to the subsystem through the address bar. Then the subsystem calls the interface through this code to obtain the access-token (using a blank page).

3. Expansion: 302 jumps how to SetCookie to the corresponding system.

Background: In the case of local joint debugging, the back-end setting redirects to the corresponding system, SetCookie to the development environment, and sets Domain to the IP/domain name of the development environment, but it is found that the cookie is not set.

​ Therefore, we investigated the cause and found that the Cookie was blocked because the Host in the request header of the redirected interface was inconsistent with the Domain set in the backend . The error is reported as follows:

Insert image description here

For this reason, I did a test to simulate setting cookies on Baidu's website:

  • First set up the Host file (127.0.0.1 test.baidu.com) and simulate Baidu’s domain name to the local IP;

  • Then the back-end code redirects to www.baidu.com and sets a cookie to the domain name baidu.com.

     @GetMapping("/setCookieRedirect")
        void testCookieRedirect(HttpServletResponse response) throws IOException {
          
          
            String testUrl = "http://baidu.com";
            Cookie cookie = new Cookie("testCookie","test");
            cookie.setDomain("baidu.com");
            cookie.setMaxAge(43200);
            cookie.setSecure(false);
            cookie.setHttpOnly(false);
            response.addCookie(cookie);
            response.sendRedirect(testUrl);
        }
    
  • Important : When the front-end calls the back-end interface, it cannot be called with localhost, but with the domain name test.baidu.com , as follows:

     const testThirdCookie = ()=>{
          
          
        window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
      }
    

Finally, the cookie was successfully set to Baidu, and the effect is as follows:

Insert image description here

Summary: The key is that the host in the request header must be consistent with the set Domain object domain name, or the parent domain name includes the sub-level domain name.

   const testThirdCookie = ()=>{
    
    
      window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
    }

Finally, the cookie was successfully set to Baidu, and the effect is as follows:Insert image description here

Summary: The key is that the host in the request header must be consistent with the set Domain object domain name, or the parent domain name includes the sub-level domain name.

Guess you like

Origin blog.csdn.net/m0_65035567/article/details/131332346