Single sign-on (SSO), as the name implies, a user only needs to log in once to access all trusted applications in multiple application systems. The traditional SSO implementation method is the combination of cookie and session. This article mainly introduces the process of using accessToken+localStorage to achieve SSO

Application scenarios

First, let’s introduce the application scenarios. Account Login Authorization system (Account.example.com) is used to authorize login of other applications and maintain account information. System A(A.example.com) and system B(B.example.com) use the account login authorization system to authorize login. The following functions need to be implemented:

  • Function 1: After you log in to system A, system B is logged in by default
  • Function 2: After logging out of system B, system A also logs out
  • Function 3: When system A or B needs to modify user information, A Tab page is created and the user information is modified in the account login authorization system. The modified user information is synchronized to system A or B

Note: The implementation of web-side authorized login will not be covered in this blog, but will be explained in detail in the next blog

Thought analysis

After a successful login, the application stores the obtained user information in a persistent manner to prevent users from losing their login information after refreshing the page. In this way, users can log in repeatedly. Generally, data persistence on the Web side uses sessionStorage, localStorage or cookies. Their advantages and disadvantages are as follows:

  • SessionStorage is generated by the browser and is valid only in the current session. It is cleared after the page or browser is closed. The storage size is 5M
  • LocalStorage is generated by the browser and stored permanently unless the browser is deleted or uninstalled. The storage size is 5M
  • Cookies are generally generated by the server and the expiration time can be set. If cookies are generated on the browser side, they will be invalid after the browser is closed by default and the storage size is 4K

While the above three methods of data persistence all meet our requirements, they have a common limitation that they cannot synchronize across domains. For example, after A successful login, system A stores the user login information to the localStorage under domain a.example.com, whereas system B obtains the localStorage under domain b.example.com. Therefore, to implement single sign-on and data synchronization problems, Cross-domain data synchronization for localStorage must be resolved. Foreshadowing so much, finally to lead to the content of this blog focus, is the cross-domain synchronization of localStorage.

Cross-domain synchronization of localStorage

Cross-domain synchronization problem with localStorageA Google search will bring up many blogs that explain how to do this, and Github has many open source projects that address the cross-domain synchronization of localStorage, such as Star’s 1.9Kcross-storage.cross-domain-local-storageThe general idea of these solutions is to embed and load the IFrame of a common domain in the Web pages of multiple different domains, and use the postMessage of the window object of the IFrame to communicate, so as to achieve the cross-domain synchronization of localStorage of the Web pages of multiple different domains. The diagram is as follows:

Taking cross-storage as an example, the setItem, getItem, removeItem, and clear operations on the shared localStorage are implemented. The setItem and getItem operations can implement function 1 in the application scenario, but function 2 and function 3 cannot be implemented. Because the existing open source libraries do not provide the function of listening to the changes of the key and value in localStorage. Therefore, in order to realize the monitoring of cross-domain localStorage, we need to build a wheels-cross-domain-shared-local-storage with more complete functions. The implementation idea refers to cross-storage and adds the function of monitoring data changes. Let me take a closer look at the open source library.

The sample

To implement cross-domain data sharing using cross-domain-shared-local-storage, we need to understand two important objects: CrossDomainStorageHub and CrossDomainStorageClient. CrossDomainStorageHub is similar to the Server in C/S mode. It is an object that needs to be initialized in iframe and is mainly used to process requests sent by postMessage in CrossDomainStorageClient. CrossDomainStorageClient is a Client in C/S mode. It sends postMessage and sends instructions to the CrossDomainStorageHub. First of all, we implemented the iframe load HTML file, we tentatively name: hub. HTML, deploy the address is: http://test.example.com/hub.html

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Demo</title>
</head>
<body>
    <script src=".. /lib/hub.min.js"></script>
    <script>
        CrossDomainStorageHub.getInstance().init([
            origin: "/\.example.com$/".// The domain that allows communication, the regular object
            allow: [ "get"."set"."del"."clear"."observed"."unobserved"].// Allows the operation origin does
        ]);
    </script>
</body>
</html>
Copy the code

In hub.html, StorageHub is mainly initialized. Initialization parameters are explained as follows:

  • Origin is of type RegExp and sets which domains are allowed to communicate with localStorage across domains

  • The allow type is string[]. The following items can be set:

    • Get: The value of the share localStorage can be obtained
    • Set indicates that the value in the share localStorage can be set
    • Del indicates that the value in the share localStorage can be deleted
    • Clear: Clears all values in the share localStorage
    • Observed indicates that the user can subscribe to the monitoring of value changes in the shared localStorage
    • Unobserved means that you can unsubscribe from listening for value changes in the shared localStorage

    Next we implement the Client part of a.example.com

    import { CrossDomainStorageClient, IStorageChange } from 'cross-domain-shared-storage';
    
    // Establish a connection and obtain the client object
    const client = await CrossDomainStorageClient.getInstance().connect('http://test.example.com/hub.html', { timeout: 5000 });
    
    // register to listen for changes in the share localStorage where key is curUser
    client.subscribeItems([ 'curUser'].(ev: IStorageChange) = >
    {
      const { newValue, oldValue } = ev;
      
      if(newValue ! == oldValue && ! oldValue)// Indicates that the user has never logged in successfully
      {
           // Perform related operations after the user logs in successfully
      }
      else if(newValue ! == oldValue && oldValue)// Indicates that the information of the current login user is modified
      {
          // Synchronize the modified user information to StateTree
      }
      else if(newValue ! == oldValue && ! newValue)// Indicates that the current user logs out
      {
          // Perform operations related to user logout}});// Set user information
    const result = await client.setItem('curUser', curUserJsonStr);
    
    // Get the current user information
    const curUserJsonStr = await client.getItem('curUser');
    
    // Clear the current user information
    const result = await client.removeItem('curUser');
    Copy the code

    API

    CrossDomainStorageHub.prototype.init(permissions)

    Initialize the CrossDomainStorageHub object method and accept an array of permission objects with key origin and allow. Origin should be RegExp, and Allow should be a string array

    CrossDomainStorageClient.prototype.connect(url, [opts])

    Establish communication with the CrossDomainStorageHub object in the iframe, the URL is the url loaded by the iframe, and accept an options object in which you can set timeout (default timeout is 5000ms). The result is a CrossDomainStorageClient instance object wrapped in Promise

    CrossDomainStorageClient.prototype.setItem(key, value)

    Write the value of the specified key to the cross-domain share localStorage. Both key and value are strings. Return Promise< Boolean >

    CrossDomainStorageClient.prototype.getItem(key)

    Get the value of the specified key in the cross-domain share localStorage, return Promise

    CrossDomainStorageClient.prototype.removeItem(key)

    Clear the value of the specified key in the cross-domain share localStorage, return Promise< Boolean >

    CrossDomainStorageClient.prototype.clear()

    Clear all key-value pairs in the cross-domain share localStorage, return Promise< Boolean >

    CrossDomainStorageClient.prototype.subscribeItems(keys, callback)

    Subscribe to listen for changes in the value of the specified key in the cross-domain share localStorage. Keys is the collection of arrays to listen for keys

    CrossDomainStorageClient.prototype.unsubscribeItems()

    Unsubscribe from listening for value changes in the cross-domain share localStorage