Embed and share console pages

更新时间:
复制 MD 格式

Generate passwordless, logon-free links to share Simple Log Service pages (query results, dashboards) with other users or embed them into third-party systems.

Notes

Concepts

A passwordless and logon-free link consists of a fixed URL, configuration parameters, and an access credential (a short-lived, single-use token). Users with the link can access query and analysis pages or dashboards without logging on to Alibaba Cloud.

The following example shows the format of the URL:

https://sls.console.aliyun.com/lognext/project/${ProjectName}/logsearch/${LogstoreName}?parameter1&parameter2
Note
  • All parameters except ${ProjectName}, ${LogstoreName}, ${savedsearchID}, and ${dashboardID} must be placed after the question mark (?) at the end of the URL.

  • You can set multiple parameters. Use ampersands (&) to separate the parameters.

  • The URL parameters are case-sensitive.

  • Available parameters are described in Configure parameters for embedding console pages.

Required permission settings

  1. If you use a Resource Access Management (RAM) user, grant permissions based on your scenario as described in the following table:

    Important

    The generated link inherits the permissions of the user who calls the CreateTicket operation in Simple Log Service. To prevent data security risks that can occur if you use an Alibaba Cloud account to call the operation, we recommend that you use a RAM user.

    Scenario

    Authorization procedure

    Generate a single link

    1. Grant permissions on specific resources by following Examples of custom policies.

    2. Grant the CreateTicket permission by following Grant permissions to a RAM user and Create a custom policy.

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "log:CreateTicket",
                "Resource": "acs:log:*:*:ticket/*"
            }
        ]
    }

    Dynamically generate links

    1. Create a RAM user and create a RAM role for a trusted Alibaba Cloud account.

    2. Grant the AliyunSTSAssumeRoleAccess permission to the RAM user. Grant the permissions to call the CreateTicket operation and the permissions related to Simple Log Service to the RAM role. For more information, see Grant permissions to a RAM role and Examples of custom policies.

    Extend the validity period of a link

    1. Log on to the RAM console as the RAM user who generated the link.

    2. Grant the RAM user the RefreshToken permission by following Grant permissions to a RAM user and Create a custom policy.

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "log:RefreshToken",
                "Resource": "acs:log:*:*:ticket/*"
            }
        ]
    }
  2. Your Alibaba Cloud account has full permissions by default. No configuration is required.

Generate a single link

To temporarily share a page, generate a one-time passwordless link using the following steps.

Generate a ticket and create a passwordless and logon-free link

Step 1: Prepare the link

  • Query and analysis page:

    https://sls.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true

    Get the project name from Manage a project, the Logstore name from Manage a Logstore, and the region ID from Endpoints.

  • Query page:

    https://sls.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true
  • Dashboard page:

    Note

    The Dashboard ID is the ID in the URL, not the display name. You can also use the Share a dashboard without a password feature in the SLS console.

    https://sls.console.aliyun.com/lognext/project/<Project name>/dashboard/<Dashboard ID>?slsRegion=<Project region>&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true

Step 2: Get a ticket credential

Call the CreateTicket operation to obtain a ticket. You must select the China (Shanghai) or Singapore endpoint to call this operation. However, the obtained ticket can be used in any region. Each generated ticket can be accessed only by the same browser or host. The ticket is valid for one day by default and for a maximum of 30 days.

image

Step 3: Create the link

  1. Concatenate the link from Step 2 with the Ticket to generate a link for passwordless and logon-free access.

    https://sls.console.aliyun.com/lognext/project/<Project name>/dashboard/<Dashboard ID>?slsRegion=<Project region>&sls_ticket=eyJ***************.eyJ******************.KUT****************&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true
  2. Test the link. You can enter the generated link in your browser's address bar to test it. If the shared Simple Log Service console page opens, the logon-free link was successfully generated.

    Important
    • This test is the first time you open the logon-free link in a browser. After the test, the ticket becomes invalid. You must obtain a new ticket.

    • We recommend that you copy the link to a file and then transfer the file. If you send the link directly in a third-party application, the link may become invalid if the application reads it.

Dynamically generate links for third-party embedding

When embedding a console page in a third-party system, dynamically call the CreateTicket operation to obtain a new ticket before the current one expires. Use a RAM role with a temporary STS token instead of a RAM user AccessKey pair to reduce security risks.

How to dynamically generate a ticket

Note
  • A ticket is valid for 24 hours by default and for a maximum of 30 days.

  • There is no limit on the total number of tickets you can generate. The queries per second (QPS) limit for the CreateTicket operation is 10 calls per second per user.

  1. Use a RAM role to call the CreateTicket operation.

    1. Use a RAM user to call the AssumeRole operation to obtain a SecurityToken, AccessKeySecret, and AccessKeyId.

    2. The RAM user uses these three parameters to assume the RAM role and then call the CreateTicket operation to obtain a ticket.

      SDK examples

      Java

      1. Add Maven dependencies.

        In the root directory of your Java project, open the pom.xml file and add the following code:

            <dependency>
              <groupId>com.aliyun</groupId>
              <artifactId>sls20201230</artifactId>
              <version>5.2.1</version>
            </dependency>
            <dependency>
              <groupId>com.aliyun</groupId>
              <artifactId>tea-openapi</artifactId>
              <version>0.3.2</version>
            </dependency>
            <dependency>
              <groupId>com.aliyun</groupId>
              <artifactId>tea-console</artifactId>
              <version>0.0.1</version>
            </dependency>
            <dependency>
              <groupId>com.aliyun</groupId>
              <artifactId>tea-util</artifactId>
              <version>0.2.21</version>
            </dependency>
      2. Use the AccessKey pair of a RAM user to create the code for generating a ticket. This method poses high security risk if the AccessKey pair is exposed. For other methods, use Manage access credentials.

        import com.aliyun.tea.*;
        
        public class Sample {
        
            /**
             * Use an AccessKey pair to initialize the client.
             * @return Client
             * @throws Exception
             */
            public static com.aliyun.sls20201230.Client createClient() throws Exception {
                // Leaking project code may compromise the security of all resources in your account by exposing the AccessKey pair. The following sample code is for reference only.
                // We recommend that you use the more secure STS method.
                com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                        // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured in your runtime environment.
                        .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
                        // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured in your runtime environment.
                        .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
                // For more information about endpoints, see https://api.aliyun.com/product/Sls.
                config.endpoint = "cn-shanghai.log.aliyuncs.com";
                return new com.aliyun.sls20201230.Client(config);
            }
        
            public static void main(String[] args_) throws Exception {
                java.util.List<String> args = java.util.Arrays.asList(args_);
                com.aliyun.sls20201230.Client client = Sample.createClient();
                com.aliyun.sls20201230.models.CreateTicketRequest createTicketRequest = new com.aliyun.sls20201230.models.CreateTicketRequest();
                com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
                java.util.Map<String, String> headers = new java.util.HashMap<>();
                try {
                    com.aliyun.sls20201230.models.CreateTicketResponse resp = client.createTicketWithOptions(createTicketRequest, headers, runtime);
                    com.aliyun.teaconsole.Client.log(com.aliyun.teautil.Common.toJSONString(resp));
                } catch (TeaException error) {
                    // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                    // Error message
                    System.out.println(error.getMessage());
                    // Troubleshooting URL
                    System.out.println(error.getData().get("Recommend"));
                    com.aliyun.teautil.Common.assertAsString(error.message);
                } catch (Exception _error) {
                    TeaException error = new TeaException(_error.getMessage(), _error);
                    // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                    // Error message
                    System.out.println(error.getMessage());
                    // Troubleshooting URL
                    System.out.println(error.getData().get("Recommend"));
                    com.aliyun.teautil.Common.assertAsString(error.message);
                }
            }
        }

      Python

      Use an STS token to create the code for generating a ticket. This method is safer because access is denied after the token expires. For other methods, use Manage access credentials.

      # -*- coding: utf-8 -*-
      # This file is auto-generated, don't edit it. Thanks.
      import os
      import sys
      
      from typing import List
      
      from alibabacloud_sls20201230.client import Client as Sls20201230Client
      from alibabacloud_tea_openapi import models as open_api_models
      from alibabacloud_sls20201230 import models as sls_20201230_models
      from alibabacloud_tea_util import models as util_models
      from alibabacloud_tea_util.client import Client as UtilClient
      
      
      class Sample:
          def __init__(self):
              pass
      
          @staticmethod
          def create_client() -> Sls20201230Client:
              """
              Use an AccessKey pair to initialize the client.
              @return: Client
              @throws Exception
              """
              # Leaking project code may compromise the security of all resources in your account by exposing the AccessKey pair. The following sample code is for reference only.
              # We recommend that you use the more secure STS method. For more information about authentication methods, see https://help.aliyun.com/document_detail/378659.html.
              config = open_api_models.Config(
                  # Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured in your runtime environment.
                  access_key_id=os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
                  # Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured in your runtime environment.
                  access_key_secret=os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
                  # Required. Make sure that the SecurityToken environment variable is configured in your runtime environment.
                  security_token=os.environ['ALIBABA_CLOUD_Token']
              )
              # For more information about endpoints, see https://api.aliyun.com/product/Sls.
              config.endpoint = f'cn-shanghai.log.aliyuncs.com'
              return Sls20201230Client(config)
      
          @staticmethod
          def main(
              args: List[str],
          ) -> None:
              client = Sample.create_client()
              create_ticket_request = sls_20201230_models.CreateTicketRequest(
                  expiration_time=300
              )
              runtime = util_models.RuntimeOptions()
              headers = {}
              try:
                  # If you copy this code to run, print the API return value yourself.
                  client.create_ticket_with_options(create_ticket_request, headers, runtime)
              except Exception as error:
                  # This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                  # Error message
                  print(error.message)
                  # Troubleshooting URL
                  print(error.data.get("Recommend"))
                  UtilClient.assert_as_string(error.message)
      
          @staticmethod
          async def main_async(
              args: List[str],
          ) -> None:
              client = Sample.create_client()
              create_ticket_request = sls_20201230_models.CreateTicketRequest(
                  expiration_time=300
              )
              runtime = util_models.RuntimeOptions()
              headers = {}
              try:
                  # If you copy this code to run, print the API return value yourself.
                  await client.create_ticket_with_options_async(create_ticket_request, headers, runtime)
              except Exception as error:
                  # This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                  # Error message
                  print(error.message)
                  # Troubleshooting URL
                  print(error.data.get("Recommend"))
                  UtilClient.assert_as_string(error.message)
      
      
      if __name__ == '__main__':
          Sample.main(sys.argv[1:])
  2. Create passwordless links with different permission scopes based on the returned ticket.

Extend link access time

Tickets have a short validity period. Use the RefreshToken operation to extend access time for a passwordless link.

Extend access time for an expired ticket

Step 1: Add a parameter to the link

Add the supportRefreshToken=true parameter to the generated link to allow the access time to be extended.

https://sls.console.aliyun.com/lognext/project/<Project name>/dashboard/<Dashboard ID>?sls_ticket=eyJ***************.eyJ******************.KUT****************&supportRefreshToken=true&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true

Step 2: Add a listener event on the client

The client listens for the message event and passes the latest accessToken to the iframe.

window.addEventListener('message', async (e) => {
  if (e?.data?.type === 'refreshToken') {
    const accessToken = await callApi()
    document.querySelector('#myIframe').contentWindow.postMessage(
      {
        // Fixed value: applyAccessToken
        type: 'applyAccessToken',
        // The accessToken returned by calling callApi()
        accessToken,
        // The ticket returned by the CreateTicket operation
        ticket: e.data.ticket,
      },
      '*'
    )
  }
})

In the client, callApi() is a custom method used to call the server-side API. The server-side API calls the RefreshToken operation to obtain an accesstoken. The following code provides an example:

Note

The RefreshToken operation has two input parameters: ticket is the ticket generated by CreateTicket. accessTokenExpirationTime specifies the expiration time of the access token generated by the operation, in seconds. The default value is 86,400 seconds (one day), and the maximum value is 86,400 seconds (one day). The validity of the ticket can be extended for up to 30 days. After 30 days, the ticket expires.

Java

  1. Add Maven dependencies.

    In the root directory of your Java project, open the pom.xml file and add the following code:

        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>sls20201230</artifactId>
          <version>5.2.1</version>
        </dependency>
        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>tea-openapi</artifactId>
          <version>0.3.2</version>
        </dependency>
        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>tea-console</artifactId>
          <version>0.0.1</version>
        </dependency>
        <dependency>
          <groupId>com.aliyun</groupId>
          <artifactId>tea-util</artifactId>
          <version>0.2.21</version>
        </dependency>
  2. Generate an accessToken.

    // This file is auto-generated, don't edit it. Thanks.
    package com.aliyun.sample;
    
    import com.aliyun.sls20201230.Client;
    import com.aliyun.tea.*;
    
    public class Sample {
    
        /**
         * Use an AccessKey pair to initialize the client.
         * @return Client
         * @throws Exception
         */
        public static Client createClient() throws Exception {
            // Leaking project code may compromise the security of all resources in your account by exposing the AccessKey pair. The following sample code is for reference only.
            // We recommend that you use the more secure STS method.
            com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured in your runtime environment.
                    .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
                    // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured in your runtime environment.
                    .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
            // For more information about endpoints, see https://api.aliyun.com/product/Sls. The endpoint must be in China (Shanghai) or Singapore.
            config.endpoint = "cn-shanghai.log.aliyuncs.com";
            return new Client(config);
        }
    
        public static void main(String[] args_) throws Exception {
            java.util.List<String> args = java.util.Arrays.asList(args_);
            com.aliyun.sls20201230.Client client = Sample.createClient();
            com.aliyun.sls20201230.models.RefreshTokenRequest refreshTokenRequest = new com.aliyun.sls20201230.models.RefreshTokenRequest()
                    .setTicket("eyJ***************.eyJ******************.KUT****************")
                    .setAccessTokenExpirationTime(60L);
            com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
            java.util.Map<String, String> headers = new java.util.HashMap<>();
            try {
                com.aliyun.sls20201230.models.RefreshTokenResponse resp = client.refreshTokenWithOptions(refreshTokenRequest, headers, runtime);
                com.aliyun.teaconsole.Client.log(com.aliyun.teautil.Common.toJSONString(resp));
            } catch (TeaException error) {
                // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                // Error message
                System.out.println(error.getMessage());
                // Troubleshooting URL
                System.out.println(error.getData().get("Recommend"));
                com.aliyun.teautil.Common.assertAsString(error.message);
            } catch (Exception _error) {
                TeaException error = new TeaException(_error.getMessage(), _error);
                // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                // Error message
                System.out.println(error.getMessage());
                // Troubleshooting URL
                System.out.println(error.getData().get("Recommend"));
                com.aliyun.teautil.Common.assertAsString(error.message);
            }        
        }
    }
    

Python

# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import os
import sys

from typing import List

from alibabacloud_sls20201230.client import Client as Sls20201230Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_sls20201230 import models as sls_20201230_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient


class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client() -> Sls20201230Client:
        """
        Use an AccessKey pair to initialize the client.
        @return: Client
        @throws Exception
        """
        # Leaking project code may compromise the security of all resources in your account by exposing the AccessKey pair. The following sample code is for reference only.
        # We recommend that you use the more secure STS method.
        config = open_api_models.Config(
            # Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured in your runtime environment.
            access_key_id=os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'],
            # Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured in your runtime environment.
            access_key_secret=os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
        )
        # For more information about endpoints, see https://api.aliyun.com/product/Sls. The endpoint must be in China (Shanghai) or Singapore.
        config.endpoint = 'cn-shanghai.log.aliyuncs.com'
        return Sls20201230Client(config)

    @staticmethod
    def main(
        args: List[str],
    ) -> None:
        client = Sample.create_client()
        refresh_token_request = sls_20201230_models.RefreshTokenRequest(
            ticket='eyJ***************.eyJ******************.KUT****************',
            access_token_expiration_time=60
        )
        runtime = util_models.RuntimeOptions()
        headers = {}
        try:
            # If you copy this code to run, print the API return value yourself.
            client.refresh_token_with_options(refresh_token_request, headers, runtime)
        except Exception as error:
            # This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
            # Error message
            print(error.message)
            # Troubleshooting URL
            print(error.data.get("Recommend"))
            UtilClient.assert_as_string(error.message)

    @staticmethod
    async def main_async(
        args: List[str],
    ) -> None:
        client = Sample.create_client()
        refresh_token_request = sls_20201230_models.RefreshTokenRequest(
            ticket='eyJ***************.eyJ******************.KUT****************',
            access_token_expiration_time=60
        )
        runtime = util_models.RuntimeOptions()
        headers = {}
        try:
            # If you copy this code to run, print the API return value yourself.
            await client.refresh_token_with_options_async(refresh_token_request, headers, runtime)
        except Exception as error:
            # This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
            # Error message
            print(error.message)
            # Troubleshooting URL
            print(error.data.get("Recommend"))
            UtilClient.assert_as_string(error.message)


if __name__ == '__main__':
    Sample.main(sys.argv[1:])

Adjust the page display

Adjust embedded page display using UI parameters described in Configure parameters for embedding console pages.

Display dashboards on a large screen

For long-term large-screen display, use the passwordless sharing and integration of dashboards feature.

  1. In the Simple Log Service console, quickly create a dashboard.

  2. Create a passwordless share and select "Long-term" for the validity period.

    2024-09-05_15-22-20 (3)

  3. Open the shared link and select full screen on your display. You can also set a refresh interval to refresh the data in real time.

Dashboard sharing and collaboration

View shared dashboards on a PC, DingTalk, WeCom, or Ali-Ding. Share dashboards with other Alibaba Cloud accounts, RAM users, DingTalk accounts, WeCom accounts, or Ali-Ding users.

Scenario 1: Share a dashboard between accounts

A team has multiple Alibaba Cloud accounts. RAM-User-A under Account A wants to share a dashboard with RAM-User-B under Account B for viewing.

  1. In the Simple Log Service console, RAM-User-A creates a dashboard and clicks Create Passwordless Share. For Access Restriction, select "Alibaba Cloud account". For Alibaba Cloud Account ID, enter the Account ID of RAM-User-B.image

  2. RAM-User-B logs on and opens the shared link to view the dashboard.

Scenario 2: Share a dashboard between applications

A company uses DingTalk or WeCom for work. The O&M team creates a dashboard in the console and shares it with developers to view in their DingTalk or WeCom accounts.

  1. Use a DingTalk organization administrator or a WeCom administrator to scan the code and activate the application.

    image

  2. Log on to the console with an Alibaba Cloud account and click image on the right side of the homepage.

    image

  3. A RAM user creates a passwordless share for the dashboard. To do this, set Access Restrictions to DingTalk Account and select the user accounts that can access the dashboard. You can also select All.image

  4. The shared DingTalk users can view the dashboard directly on the DingTalk PC client or mobile app without logging on to Alibaba Cloud.

    1. On the Workbench page in DingTalk, click the All tab, then click SLS Share & Logon-free.

      image

      image

    2. Click View Details.

      image

      image

  5. Alternatively, after logging on to DingTalk, users can view the dashboard directly in a browser using the shared link.

    1. The RAM user who is sharing copies the dashboard link and sends it to the DingTalk user.image

    2. Paste the link into the browser's address bar to view it.

Separate permissions for embedded pages

When embedding query results or dashboards into a third-party system, you can separate user permissions. The following scenarios describe the steps.

Scenario 1: Users have the same permissions

Scenario: Embed two Logstores from the same project. All users have read-only permissions for the specified Logstores and read-only permissions for saved searches and dashboards in the project.

Procedure

  1. Create a RAM user named sls-user as the sharer. Create a RAM user.

  2. Grant permissions to the RAM user sls-user.

    1. Create a permission policy named Allow-AccessLogstore to access specific resources (project, Logstore). Create a custom policy.

      Note

      Replace <Your Project Name>, <Your Logstore Name A>, and <Your Logstore Name B> with your actual project and Logstore names.

      {
        "Version": "1",
        "Statement": [
          {
            "Action": [
              "log:ListProject"
            ],
            "Resource": "acs:log:*:*:project/*",
            "Effect": "Allow"
          },
          {
            "Action": [
              "log:List*"
            ],
            "Resource": "acs:log:*:*:project/<Your Project Name>/logstore/*",
            "Effect": "Allow"
          },
          {
            "Action": [
              "log:Get*",
              "log:List*"
            ],
            "Resource": [
              "acs:log:*:*:project/<Your Project Name>/logstore/<Your Logstore Name A>",
              "acs:log:*:*:project/<Your Project Name>/logstore/<Your Logstore Name B>"
            ],
            "Effect": "Allow"
          },
          {
            "Action": [
              "log:Get*",
              "log:List*"
            ],
            "Resource": [
              "acs:log:*:*:project/<Your Project Name>/dashboard",
              "acs:log:*:*:project/<Your Project Name>/dashboard/*"
            ],
            "Effect": "Allow"
          },
          {
            "Action": [
              "log:Get*",
              "log:List*"
            ],
            "Resource": [
              "acs:log:*:*:project/<Your Project Name>/savedsearch",
              "acs:log:*:*:project/<Your Project Name>/savedsearch/*"
            ],
            "Effect": "Allow"
          }
        ]
      }
    2. Grant the Allow-AccessLogstore permission to the RAM user sls-user. Users accessing the embedded page inherit this permission. Examples of custom policies.

    3. Create a permission policy named Allow-CreateTicket to call the CreateTicket operation. Create a custom policy.

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "log:CreateTicket",
                  "Resource": "acs:log:*:*:ticket/*"
              }
          ]
      }
    4. Grant the Allow-CreateTicket permission to the RAM user. Grant permissions to a RAM user.

  3. You can create a Logstore selection box or tab in your own frontend page to switch between Logstores.

  4. When a user enters the embedded page, use the RAM user sls-user-a to call the CreateTicket operation to obtain a ticket. The following example uses the Java SDK.

    Note

    You can debug the operation on the CreateTicket page to obtain a ticket. Append the obtained ticket to the query page URL to access it.

    1. Add Maven dependencies.

      In the root directory of your Java project, open the pom.xml file and add the following code:

      <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>sls20201230</artifactId>
        <version>5.5.0</version>
      </dependency>
    2. You can download the latest sample project from the CreateTicket page. This example creates the code to generate a ticket, as shown below.

      package com.aliyun.sample;
      
      import com.aliyun.tea.*;
      
      public class Sample {
          public static com.aliyun.sls20201230.Client createClient() throws Exception {
              com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                      // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID environment variable is configured in your runtime environment.
                      .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
                      // Required. Make sure that the ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variable is configured in your runtime environment.
                      .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
              // For more information about endpoints, see https://api.aliyun.com/product/Sls.
              config.endpoint = "cn-shanghai.log.aliyuncs.com";
              return new com.aliyun.sls20201230.Client(config);
          }
      
          public static void main(String[] args_) throws Exception {
              java.util.List<String> args = java.util.Arrays.asList(args_);
              com.aliyun.sls20201230.Client client = Sample.createClient();
              com.aliyun.sls20201230.models.CreateTicketRequest createTicketRequest = new com.aliyun.sls20201230.models.CreateTicketRequest();
              com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
              java.util.Map<String, String> headers = new java.util.HashMap<>();
              try {
                  // If you copy this code to run, print the API return value yourself.
                  com.aliyun.sls20201230.models.CreateTicketResponse createTicketResponse = client.createTicketWithOptions(createTicketRequest, headers, runtime);
                  
      System.out.println(createTicketResponse.getBody().getTicket());
              } catch (TeaException error) {
                  // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                  // Error message
                  System.out.println(error.getMessage());
                  // Troubleshooting URL
                  System.out.println(error.getData().get("Recommend"));
                  com.aliyun.teautil.Common.assertAsString(error.message);
              } catch (Exception _error) {
                  TeaException error = new TeaException(_error.getMessage(), _error);
                  // This is for printing and demonstration purposes only. Handle exceptions with caution. Do not ignore exceptions in your project.
                  // Error message
                  System.out.println(error.getMessage());
                  // Troubleshooting URL
                  System.out.println(error.getData().get("Recommend"));
                  com.aliyun.teautil.Common.assertAsString(error.message);
              }        
          }
      }
      
  5. Append the obtained ticket to the query page URL. You can also hide the sidebar and top bar, and disable tab history (hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true). Configure parameters for embedding console pages.

    https://sls.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true&sls_ticket=eyJ***************.eyJ******************.KUT****************
  6. To switch Logstores, you can reuse the generated ticket in the same browser by appending it to the URL.

    Note

    You do not need to call the operation again in the same browser. Different users (in different browsers) still need to call CreateTicket again. A ticket can be accessed only by one browser or host.

Scenario 2: Users have different permissions

Scenario: Embed two projects. User A has read-only access to Project-A, and User B has read-only access to Project-B.

Procedure

  1. Create a RAM user named sls-user as the sharer. Create a RAM user.

  2. Grant the AliyunSTSAssumeRoleAccess permission to the RAM user sls-user to call the STS AssumeRole operation. Grant permissions to a RAM user.

  3. Create a RAM role named sls-role. Create a RAM role for a trusted Alibaba Cloud account.

  4. Grant the RAM role sls-role permissions on specific resources (projects) and permission to call the CreateTicket operation.

    1. Create a permission policy named Allow-AccessProject to access specific resources (projects). The permission is the union of all user permissions (Create a custom policy). In this case, read-only access to Project-A and Project-B is required. The following code shows the policy:

      Note

      Replace <Your Project Name A> and <Your Project Name B> with your actual project names.

      {
         "Version": "1",
         "Statement": [
           {
             "Action": [
               "log:Get*",
               "log:List*"
             ],
             "Resource": [
               "acs:log:*:*:project/<Your Project Name A>/*",
               "acs:log:*:*:project/<Your Project Name A>",
               "acs:log:*:*:project/<Your Project Name B>/*",
               "acs:log:*:*:project/<Your Project Name B>"
             ],
             "Effect": "Allow"
           }
         ]
      }
    2. Grant the Allow-AccessProject permission to the RAM role sls-role. Grant permissions to a RAM role.

    3. Create a permission policy named Allow-CreateTicket to call the CreateTicket operation. Create a custom policy.

      {
          "Version": "1",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "log:CreateTicket",
                  "Resource": "acs:log:*:*:ticket/*"
              }
          ]
      }
    4. Grant the Allow-CreateTicket permission to the RAM role sls-role. Grant permissions to a RAM role.

  5. Set the maximum session duration for the RAM role. The default is 1 hour. The validity period of the embedded page will be less than this time.

    image.png

  6. When a user enters the embedded page, use the RAM user sls-user to assume the RAM role sls-role and call the AssumeRole operation. You must set the following four parameters.

    Field Name

    Description

    RoleArn

    The Alibaba Cloud Resource Name (ARN) of the RAM role to assume. Copy this from the RAM role.

    RoleSessionName

    The name of the role session. This can be any string, such as a user ID or name, to distinguish different users for auditing.

    DurationSeconds

    The validity period of the token. The minimum is 900 seconds, and the maximum is the maximum session duration of the RAM role. The default is 3,600 seconds.

    Policy

    An additional permission policy for the STS token.

    • If you specify this policy, the final permission policy of the STS token is the intersection of the RAM role's permission policy and this policy.

    • If you do not specify this policy, the final permission policy of the STS token is the RAM role's permission policy.

    When calling, set a different policy for each user. This adds an additional permission policy for the STS token. The final permission policy of the STS token is the intersection of the RAM role's permission policy and this policy. For example, when User A enters the embedded page, set RoleSessionName to UserA and the policy to:

    {
       "Version": "1",
       "Statement": [
         {
           "Action": [
             "log:Get*",
             "log:List*"
           ],
           "Resource": [
             "acs:log:*:*:project/<Your Project Name A>/*",
             "acs:log:*:*:project/<Your Project Name A>"
           ],
           "Effect": "Allow"
         },
         {
            "Effect": "Allow",
            "Action": "log:CreateTicket",
            "Resource": "acs:log:*:*:ticket/*"
        }
       ]
    }

    When User B enters the embedded page, set RoleSessionName to UserB and the policy to:

    {
       "Version": "1",
       "Statement": [
         {
           "Action": [
             "log:Get*",
             "log:List*"
           ],
           "Resource": [
             "acs:log:*:*:project/<Your Project Name B>/*",
             "acs:log:*:*:project/<Your Project Name B>"
           ],
           "Effect": "Allow"
         },
         {
            "Effect": "Allow",
            "Action": "log:CreateTicket",
            "Resource": "acs:log:*:*:ticket/*"
        }
       ]
    }

    After obtaining the temporary STS credentials (SecurityToken, AccessKeySecret, and AccessKeyId), use this STS to call CreateTicket to obtain a ticket. The following example uses Java:

    package com.aliyun.sls20201230;
    
    import com.aliyun.sls20201230.models.CreateTicketRequest;
    import com.aliyun.sls20201230.models.CreateTicketResponse;
    import com.aliyun.sls20201230.models.CreateTicketResponseBody;
    import com.aliyun.sts20150401.models.AssumeRoleResponse;
    import com.aliyun.sts20150401.models.AssumeRoleResponseBody;
    import com.aliyun.tea.TeaException;
    import com.aliyun.teaopenapi.models.Config;
    
    import java.util.List;
    
    public class StsSample {
        public static void main(String[] args_) throws Exception {
            List<String> args = java.util.Arrays.asList(args_);
            String roleArn = "xxxx";
            String roleSession = "UserA";
            String policy = "{\n" +
                    "   \"Version\": \"1\",\n" +
                    "   \"Statement\": [\n" +
                    "     {\n" +
                    "       \"Action\": [\n" +
                    "         \"log:Get*\",\n" +
                    "         \"log:List*\"\n" +
                    "       ],\n" +
                    "       \"Resource\": [\n" +
                    "         \"acs:log:*:*:project/<Your Project Name A>/*\",\n" +
                    "         \"acs:log:*:*:project/<Your Project Name A>\"\n" +
                    "       ],\n" +
                    "       \"Effect\": \"Allow\"\n" +
                    "     },\n" +
                    "     {\n" +
                    "        \"Effect\": \"Allow\",\n" +
                    "        \"Action\": \"log:CreateTicket\",\n" +
                    "        \"Resource\": \"acs:log:*:*:ticket/*\"\n" +
                    "    }\n" +
                    "   ]\n" +
                    "}";
            Client client = StsSample.createClient(roleArn, roleSession, policy);
            try {
                CreateTicketRequest createTicketRequest = new CreateTicketRequest();
                CreateTicketResponse response = client.createTicket(createTicketRequest);
                CreateTicketResponseBody embedded = response.getBody();
                System.out.println(embedded.getTicket());
    
            } catch (TeaException e) {
                e.printStackTrace();
            }
        }
    
        public static Client createClient(String roleArn, String roleSession, String policy) throws Exception {
            com.aliyun.sts20150401.Client client = createStsClient();
            com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest();
            assumeRoleRequest.setRoleArn(roleArn);
            assumeRoleRequest.setRoleSessionName(roleSession);
            assumeRoleRequest.setDurationSeconds(3600L);
            assumeRoleRequest.setPolicy(policy);
            com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
            AssumeRoleResponse assumeRoleResponse = client.assumeRoleWithOptions(assumeRoleRequest, runtime);
            AssumeRoleResponseBody.AssumeRoleResponseBodyCredentials credentials = assumeRoleResponse.getBody().getCredentials();
    
            Config config = new Config()
                    .setAccessKeyId(credentials.getAccessKeyId())
                    .setAccessKeySecret(credentials.getAccessKeySecret())
                    .setSecurityToken(credentials.getSecurityToken())
                    // For more information about endpoints, see https://api.aliyun.com/product/Sls.
                    .setEndpoint("cn-shanghai.log.aliyuncs.com");
            return new Client(config);
        }
    
        public static com.aliyun.sts20150401.Client createStsClient() throws Exception {
            String accessKeyId = "xxx";
            String accessKeySecret = "xxx";
            com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                    .setAccessKeyId(accessKeyId)
                    .setAccessKeySecret(accessKeySecret);
            // For more information about endpoints, see https://api.aliyun.com/product/Sts.
            config.endpoint = "sts.cn-shanghai.aliyuncs.com";
            return new com.aliyun.sts20150401.Client(config);
        }
    }
    
  7. Append the obtained ticket to the query page URL. You can also hide the sidebar and top bar, and disable tab history (hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true). Configure parameters for embedding console pages.

    https://sls.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true&sls_ticket=eyJ***************.eyJ******************.KUT****************

Permission settings for multiple embedded pages

Multiple embedded pages with the same permissions

  1. You can generate one ticket and refresh the pages in the same browser. When the ticket expires, generate a new ticket and replace the expired ticket on all tab pages.

  2. Different browsers or computers are considered different users. Because a ticket can be used to open a link in a browser only once, the following error is reported:

    {"code":"TicketUnavailable","message":"There are no more tickets available.","requestId":"xxxxxx","success":false}

Multiple embedded pages with different permissions

  1. You can generate multiple tickets, each associated with different permissions. However, you can only refresh the embedded page corresponding to the last ticket. This is because only one cookie can be recorded as the credential for the current user, which corresponds to the last generated ticket. Each refresh uses this cookie to identify the current user.

  2. If you do not refresh the page, cookies are not needed. You can still switch between tabs and operate on the content of different embedded pages with their corresponding permissions.

  3. If you refresh an embedded page that does not correspond to the last ticket, the following error is reported:

    {"code":"TicketUnavailable","message":"There are no more tickets available.","requestId":"xxxxxx","success":false}

Generate a passwordless and logon-free link (old version)

The following legacy method also works but relies on third-party cookies and is slower than the new method: Generate a single passwordless and logon-free link. All other scenarios in this topic use the new method.

Note
  • This feature only supports access by assuming a RAM role.

  • Due to backend validation logic, we recommend that you regenerate the console sharing link 5 minutes before the SigninToken expires to continue using the logon-free page. Otherwise, the logon-free page reports a SigninToken error when the SigninToken expires.

Step 1: Create a RAM role and a RAM user

Create a RAM role and grant it view permissions for the shared page. Then, create a RAM user and grant it permission to assume the RAM role.

  1. Create a RAM role that can be assumed by a RAM user or another RAM role under the current Alibaba Cloud account. Use a RAM role to access resources across Alibaba Cloud accounts.

  2. Grant permissions to the RAM role to allow it to access the shared link. For example, grant read-only permissions for SLS.

    {
        "Version": "1",
        "Statement": [
            {
                "Action": [
                    "log:Get*",
                    "log:List*",
                    "log:Query*"
                ],
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }
  3. Record the ARN of the RAM role, such as acs:ram::137******44:role/role-name.

  4. To create a RAM user, see Create and authorize a RAM user. When creating the user, select the OpenAPI Call Access option. After the user is created, record the AccessKey pair.

  5. Grant the RAM user permission to assume the role.

    Note

    For Resource, specify the ARN of the created RAM role.

    {
        "Version": "1",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "sts:AssumeRole",
                "Resource": "acs:ram::137******44:role/role-name"
            }
        ]
    }

Step 2: Prepare the shareable link

  • Query and analysis page:

    https://sls4service.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true
  • Query page:

    https://sls4service.console.aliyun.com/lognext/project/<Project name>/logsearch/<Logstore name>?slsRegion=<Project region>&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true
  • Dashboard page:

    https://sls4service.console.aliyun.com/lognext/project/<Project name>/dashboard/<Dashboard ID>?slsRegion=<Project region>&isShare=true&hideTopbar=true&hideSidebar=true&ignoreTabLocalStorage=true
    Note

    The Dashboard ID is the ID from the dashboard URL, not its display name. You can also use the Share a dashboard without a password feature in the SLS console.

  • Full-stack observability application page

    The following example uses the Trace Analysis page. For more information, see Embed full-stack observability pages.

    https://sls4service.console.aliyun.com/lognext/app/observability/trace/<Project name>/<Full-stack observability instance ID>?resource=/trace/<Full-stack observability instance ID>/explorer&hideTopbar=true&isShare=true

Step 3: Generate the logon-free link

Create the logon-free link. For code examples in Java, Python, and other languages, see Code examples.

  1. Use the RAM user's AccessKey to access the STS service and exchange it for a Security Token Service (STS) token. A token can be used only once. You can specify the validity period of the token. The following code shows an example of how to obtain an STS token.

    DefaultProfile.addEndpoint("", "", "Sts", stsHost);
    IClientProfile profile = DefaultProfile.getProfile("", <AccessKeyId>, <AccessKeySecret>);
    DefaultAcsClient client = new DefaultAcsClient(profile);
    AssumeRoleRequest assumeRoleReq = new AssumeRoleRequest();
    assumeRoleReq.setRoleArn(roleArn); // ARN of the RAM role
    assumeRoleReq.setRoleSessionName(roleSession);
    assumeRoleReq.setMethod(MethodType.POST);
    assumeRoleReq.setDurationSeconds(3600L);
    AssumeRoleResponse assumeRoleRes = client.getAcsResponse(assumeRoleReq);
  2. Call RAM single sign-on (SSO) to obtain a logon token. The link format is as follows. Note: TicketType must be set to mini.

    http://signin.aliyun.com/federation?Action=GetSigninToken
                        &AccessKeyId=<Temporary AK returned by STS>
                        &AccessKeySecret=<Temporary secret returned by STS>
                        &SecurityToken=<Security token returned by STS>
                        &TicketType=mini

    The returned structure is as follows:

    {
        "RequestId": "02b47c77c5fd48789d23773af853e9f7_936be_1706585994094_1.229",
        "SigninToken": "svX6LGcBbWLExKD5hcwdLu6RsLQbv36fWZN36WhxkTXpTcDpmzs2K6X8uFvCqGsBTU4KWJMffYz2rAVbdJXHMECgUfyzS869wh2DBdFEQo3e2fJgZ5YtcMSVnoX7pterS2f7926jFvdBXVFEF54JkUCMrDAutNRv1u7ZReC7v8oQoG5UmjJBbHUyvLTn5UDDvDfNowMVyRskrZRFUKT2qAMZ4Gnc****"
    }
  3. Append the returned logon token to the prepared link to generate a passwordless access link.

    http://signin.aliyun.com/federation?Action=Login
                                &LoginUrl=<The URL to which the user is redirected if the logon fails. This is typically a URL on your own web server that performs a 302 redirect. You must URL-encode the LoginUrl.>
                                &Destination=<The actual Simple Log Service page to access. Query pages and dashboard pages are supported. If there are parameters, you must URL-encode them.>
                                &SigninToken=<The obtained logon token. You must URL-encode the token.>

Code examples

  • Java sample code

    The Maven dependencies for the Java code are as follows.

    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-sts</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
        <version>3.5.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.5</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.68.noneautotype</version>
    </dependency>
  • PHP sample code

  • Python sample code

  • Go sample code

Step 4: Embed using an iframe

Embed the link into another web page using an iframe.

Important
  • This test is the first time you open the logon-free link in a browser. After the test, the logon token becomes invalid. You must regenerate the logon-free link.

  • If an error occurs with the iframe nested link, it may be because of security restrictions that prevent the loading of external websites. You can modify the Content-Security-Policy header. For example, you can use the following CSP directive to allow embedding from aliyun.com and *.aliyun.com: Content-Security-Policy: frame-ancestors 'self' aliyun.com *.aliyun.com;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Console Link Sharing</title>
</head>
<body>
<iframe width="1280" height="720" src="Logon-free access link"> </iframe>
</body>
</html>