全部產品
Search
文件中心

Application Real-Time Monitoring Service:Grafana頁面嵌入自建Web應用

更新時間:Oct 17, 2025

如需在自建Web應用中免登入查看Grafana大盤的頁面,您可將Grafana大盤嵌入自建Web應用,以避免系統間的來回切換。

使用限制

當前僅Grafana共用版頁面支援嵌入自建Web應用。

背景資訊

將Grafana大盤嵌入自建Web應用可以實現以下效果:

  • 可登入自有系統並瀏覽嵌入的Grafana大盤。

  • 可隱藏Grafana的頂部功能表列和左側導覽列。具體操作,請參見本文步驟五中的相關內容。

訪問流程

外部系統訪問Grafana的流程如下圖所示。

步驟一:建立RAM使用者並添加許可權

使用阿里雲帳號建立RAM使用者並為其添加調用STS服務扮演RAM角色的許可權。

  1. 使用阿里雲帳號(主帳號)或Resource Access Management員登入RAM控制台

  2. 在左側導覽列,選擇身份管理 > 使用者

  3. 使用者頁面,單擊建立使用者

    image

  4. 建立使用者頁面的使用者帳號資訊地區,輸入登入名稱稱顯示名稱,在訪問方式地區,選中控制台訪問,然後單擊確定

    重要

    RAM會自動為RAM使用者建立AccessKey(API存取金鑰)。出於安全考慮,RAM控制台只提供一次查看或下載AccessKeySecret的機會,即建立AccessKey時,請務必將AccessKeySecret記錄到安全的地方。

  5. 使用者頁面,單擊目標RAM使用者操作列的添加許可權

    image

    您也可以選中多個RAM使用者,單擊使用者列表下方的添加許可權,為RAM使用者大量授權。

  6. 新增授權面板的權限原則地區,添加AliyunSTSAssumeRoleAccess權限原則,然後單擊確認新增授權

  7. 單擊關閉

步驟二:建立RAM角色並添加許可權

建立RAM角色並為其添加存取控制台的許可權。RAM使用者將會扮演該RAM角色存取控制台。

  1. 建立可信實體為阿里雲帳號的RAM角色

  2. 為角色添加ARMS的完整許可權或唯讀許可權。具體操作,請參見為RAM角色授權

    • AliyunARMSFullAccess:ARMS的完整許可權。

    • AliyunARMSReadOnlyAccess:ARMS的唯讀許可權。

步驟三:擷取臨時AccessKey和Token

登入自建Web應用,然後在Web服務端調用STS的AssumeRole介面擷取臨時AccessKey和Token,即臨時身份。AssumeRole介面詳情,請參見AssumeRole

您可以選擇以下方式調用AssumeRole介面:

本文以通過Java SDK調用為例。

您在使用Java SDK時需要注意填寫以下參數:

String accessKey = "<accessKeyId>"; //RAM使用者的AccessKeyId。
String accessSecret = "<accessKeySecret>"; //RAM使用者的AccessKeySecret。
String roleArn = "<roleArn>"; //RAM角色的標識ARN。

RAM使用者的AccessKeyId和AccessKeySecret為建立RAM使用者時擷取。擷取操作,請參見建立AccessKey

擷取RAM角色的roleArn的操作步驟如下:

  1. RAM控制台身份管理 > 角色頁面下方的RAM角色列表中,單擊目標RAM角色名稱。

  2. 在RAM角色詳情頁面的基本資料地區,複製ARN資訊。

    Example ARN

步驟四:擷取登入Token

通過STS的AssumeRole介面擷取臨時AccessKey和Token後,調用登入服務介面擷取登入Token。

重要

STS返回的安全Token中可能包含特殊字元,請對特殊字元進行URL編碼後再輸入。

請求範例:

https://signin.alibabacloud.com/federation?Action=GetSigninToken
    &AccessKeyId=<STS返回的臨時AccessKeyId>
    &AccessKeySecret=<STS返回的臨時AccessKeySecret>
    &SecurityToken=<STS返回的安全Token>
說明

如果為虛商接入,則還需添加&TicketType=mini參數。

步驟五:產生免登入連結

利用擷取到的登入Token與待嵌入的Grafana大盤頁面連結產生免登入訪問連結,以最終實現在自建Web應用中免登入訪問Grafana頁面的目的。

說明

由於Token有效期間為3小時,建議在自建Web應用中將連結設定為每次請求時產生新登入Token。

  1. 在Grafana擷取待嵌入的大盤頁面的URL連結。

    說明
    • 在URL連結的search部分添加kiosk=tv可以隱藏原有的左側導覽列。

    • 在URL連結的search部分添加kiosk可以隱藏頂部功能表列和左側導覽列。

    • 在URL連結的search部分添加kiosk=tv2可以隱藏頂部功能表列和左側導覽列,但保留右上方的時間選取器。

  2. 利用登入Token與Grafana大盤連結產生免登入訪問連結。

    http://signin.alibabacloud.com/federation?Action=Login
        &LoginUrl=<登入失效跳轉的地址,一般配置為自建Web應用配置302跳轉的URL>
        &Destination=<Grafana大盤連結>
        &SigninToken=<擷取到的登入Token>
  3. 在瀏覽器訪問該免登入訪問連結。

展開查看完整的iframe url範例程式碼

/*
Copyright 2022 Alibaba Cloud.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.aliyun.arms.unifydemo.unifydemo;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.net.URLEncoder;

/**
 * @author XX
 * @version V1.0.0
 * @dept XX-XX
 * @date 2025/7/2 16:10
 * @description
 */
public class GrafanaIframeUrlGenerator {
    private static final String signInHost = "https://signin.aliyun.com";
    private static final String loginUrl = "https://www.aliyun.com";

    private static final String loginUri = "/federation?Action=Login&LoginUrl=%s&Destination=%s&SigninToken=%s";

    private static final String signInTokenUri = "/federation?Action=GetSigninToken&AccessKeyId=%s&AccessKeySecret=%s&SecurityToken=%s&TicketType=%s";

    public static void main(String[] args) {
        try {
            //請根據自己帳號角色情況自行設定,Grafana地址虛商需要加4service
            String destination = "https://gnew4servims.console.alibabacloud.com/d/1098370038******-53945-422/ack-pro-apiserver?orgId=9&refresh=60s";
            String regionId = "cn-hangzhou";//請自行設定
            String accessKey = "";  //請根據自己帳號角色情況自行設定,帳號需要有STS許可權 AliyunSTSAssumeRoleAccess
            String secretKey = "";//請根據自己帳號角色情況自行設定
            //注意:請根據自己帳號角色情況自行設定,角色需要有讀許可權 AliyunARMSReadOnlyAccess 角色許可權不足會無法訪問
            String role="acs:ram::109837003******:role/armsreadonlyforgrafanaiframe";

            /*
             * 第一步
             * */
            //設定參數,指定角色ARN,並設定Policy以進一步限制STS Token擷取的權 // acs:ram::$accountID:role/$roleName
            //構建AssumeRole請求
            AssumeRoleResponse.Credentials key = getCredentials(regionId, accessKey, secretKey, role, "role-" + System.currentTimeMillis());

            /*
             * 第二步
             * 擷取登入Token
             * */
            String token = getLoginToken(key, destination);

            /*
             * 第三步
             * 擷取免登地址
             * */
            String url = getUrl(token, destination);

            /*
             * 第四步
             * 跳轉地址
             * */
            System.out.println(url);
        } catch (Error e) {
            e.printStackTrace();
        }
    }


    private static AssumeRoleResponse.Credentials getCredentials(String regionId, String accessKey, String secretKey, String roleArn, String roleSessionName) {

        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKey, secretKey);


        IAcsClient client = new DefaultAcsClient(profile);

        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setSysMethod(MethodType.POST);
        request.setRoleArn(roleArn);
        request.setRoleSessionName(roleSessionName);
        request.setDurationSeconds(3600L);
        try {
            AssumeRoleResponse response = client.getAcsResponse(request);
            return response.getCredentials();
        } catch (Exception e) {
            throw new RuntimeException("AssumeRoleService load ErrCode:" + e.getMessage());
        }
    }


    public static String getLoginToken(AssumeRoleResponse.Credentials key, String destination) {
        String token = "";
        if (key == null) {
            return "";
        }
        String ticketType = "normal";
        if (destination == null || destination.trim().length() == 0 || destination.contains("4service")) {
            ticketType = "mini";
        }
        String signInTokenUrl = "";
        try {
            signInTokenUrl = signInHost + String.format(signInTokenUri,
                    URLEncoder.encode(key.getAccessKeyId(), "utf-8"),
                    URLEncoder.encode(key.getAccessKeySecret(), "utf-8"),
                    URLEncoder.encode(key.getSecurityToken(), "utf-8"),
                    URLEncoder.encode(ticketType, "utf-8"));
        } catch (Exception e) {
            throw new RuntimeException("SigninTokenService build signInTokenUrl error:" + e.getMessage());
        }
        final CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet signInGet = new HttpGet(signInTokenUrl);
            HttpResponse httpResponse = httpClient.execute(signInGet);
            String signInToken = "";
            if (httpResponse.getStatusLine().getStatusCode() != 200) {
                throw new RuntimeException("SigninTokenService failed to retrieve signInToken!");
            }
            String signInRes = EntityUtils.toString(httpResponse.getEntity());
            signInToken = JSON.parseObject(signInRes).getString("SigninToken");
            if (signInToken == null) {
                throw new RuntimeException("SigninTokenService signInToken is empty while signInRes is:" + signInRes);
            }
            return signInToken;
        } catch (Exception e) {
            throw new RuntimeException("SigninTokenService get signInToken error:" + e.getMessage());
        }
    }

    public static String getUrl(String token, String destination) {
        String url = "";
        try {
            url = signInHost + String.format(loginUri,
                    URLEncoder.encode(loginUrl, "utf-8"),
                    URLEncoder.encode(destination, "utf-8"),
                    URLEncoder.encode(token, "utf-8"));
        } catch (Exception e) {
            throw new RuntimeException("SigninUrlService build getUrl error:" + e.getMessage());
        }
        return url;
    }
}