OpenSearch-LLM智能问答版提供问答测试页面嵌入功能,支持将测试界面集成至自有Web应用并保留用户测试参数,同时可实现页面的免登录共享,便于团队协作测试。
基本原理
登录服务signin.aliyun.com
支持通过在URL中拼接登录Token,当用户访问链接时,首先会访问登录服务,登录服务检测到有效的登录Token后,会重定向到目标页面,实现问答测试页面的免登录访问。整体的流程如下。
用户访问您的Web服务。
Web服务端使用RAM用户的AK访问令牌服务(STS)获取安全令牌(STS Token)。
令牌服务(STS)返回安全令牌(STS Token)。
Web服务端使用安全令牌访问RAM的登录服务SSO,获取登录Token。
登录服务返回登录Token。
Web服务端拼接免登录链接,返回给客户端,客户端根据拼接的免登录链接访问OpenSearch-LLM智能问答版问答测试页面。
注意事项
在使用问答测试分享功能的过程中,请注意以下事项:
该功能仅支持通过扮演RAM角色进行访问。
由于令牌服务(STS)生成的登录Token为临时凭证,所以共享链接仅支持在浏览器中打开一次。重复打开该链接会提示SigninToken错误。
由于后端存在校验逻辑,建议您在SigninToken失效期前5分钟重新生成问答测试分享链接以持续使用免登的页面。SigninToken的默认有效期为1小时,失效后将导致免登录页面上报SigninToken错误。
操作流程
准备工作
记录下OpenSearch-LLM智能问答版问答测试页面的Destination地址:
示例:
https://opensearch4service.console.aliyun.com/llm-chat?hideTopbar=true&hideSidebar=true®ion=cn-shanghai&appName={appname}&options=%7B%22retrieve%22%3A%7B%22doc%22%3A%7B%22filter%22%3A%22%22%2C%22top_n%22%3A5%2C%22sf%22%3A%22%22%2C%22dense_weight%22%3A%220.7%22%2C%22formula%22%3A%22%22%2C%22operator%22%3A%22AND%22%7D%2C%22entry%22%3A%7B%22sf%22%3A%22%22%2C%22filter%22%3A%22%22%7D%2C%22image%22%3A%7B%22sf%22%3A%22%22%2C%22dense_weight%22%3A%220.7%22%7D%2C%22qp%22%3A%7B%22query_extend%22%3Afalse%2C%22query_extend_num%22%3A5%7D%2C%22return_hits%22%3Afalse%2C%22graph%22%3A%7B%22enable%22%3Atrue%7D%2C%22web_search%22%3A%7B%22enable%22%3Afalse%7D%2C%22rerank%22%3A%7B%22enable%22%3Atrue%2C%22model%22%3A%22ops-bge-reranker-larger%22%7D%7D%2C%22chat%22%3A%7B%22stream%22%3Atrue%2C%22prompt_config%22%3A%7B%22attitude%22%3A%22normal%22%2C%22rule%22%3A%22detailed%22%2C%22noanswer%22%3A%22sorry%22%2C%22language%22%3A%22Chinese%22%2C%22role%22%3Afalse%2C%22role_name%22%3A%22AI%E5%B0%8F%E5%8A%A9%E6%89%8B%22%2C%22out_format%22%3A%22text%22%7D%2C%22agent%22%3A%7B%22tools%22%3A%5B%5D%7D%2C%22csi_level%22%3A%22strict%22%2C%22history_max%22%3A%22%22%2C%22link%22%3A%22false%22%2C%22rich_text_strategy%22%3A%22%22%2C%22enable_llm_knowledge%22%3Atrue%7D%7D
创建RAM用户
创建RAM用户的操作步骤请参见创建RAM用户并授权。 创建时请勾选通过使用永久 AccessKey 访问选项,创建完成后记录下AccessKey。
授予RAM用户AliyunSTSAssumeRoleAccess权限用于调用STS服务。
创建RAM角色
创建RAM角色的操作步骤请参见创建RAM角色并授权。编辑信任策略,授权RAM用户扮演角色。
{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": [ "acs:ram::106******24:user/<创建的ram用户名称>" ] } } ], "Version": "1" }
授予RAM角色AliyunOpenSearchReadOnlyAccess权限用于调用STS服务。
记录下RAM角色的ARN,格式如
acs:ram::106******24:role/role-name
。
获取免登录链接
制作OpenSearch-LLM智能问答版问答测试页面的免登录链接,完整示例请参考代码示例。
通过使用RAM用户的
AccessKey
访问STS服务获取安全令牌(STS Token),可根据业务的实际需要指定令牌的有效期。获取STS Token的示例代码如下。//请填入提前准备的问答测试页面Destination地址 String DestinationUrl = ""; //请填入RAM角色的ARN String RoleArn = ""; //请填入RAM角色会话名称 String RoleSessionName = ""; com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config() // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。 .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")) // 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。 .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")); // Endpoint 请参考 https://api.aliyun.com/product/Sts config.endpoint = "sts.cn-hangzhou.aliyuncs.com"; com.aliyun.sts20150401.Client client = new com.aliyun.sts20150401.Client(config); com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest() .setRoleArn(RoleArn) .setRoleSessionName(RoleSessionName); com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); com.aliyun.sts20150401.models.AssumeRoleResponseBody resp = client.assumeRoleWithOptions(assumeRoleRequest, runtime).getBody();
调用RAM单点登录SSO,获取登录Token。拼接链接的形式如下。注意:
TicketType
必须指定为mini
。http://signin.aliyun.com/federation?Action=GetSigninToken &AccessKeyId=<STS返回的临时AK> &AccessKeySecret=<STS返回的临时Secret> &SecurityToken=<STS返回的安全Token> &TicketType=mini
返回的结构如下:
{ "RequestId": "******c5fd48789d23773af853e9f7_936be_1706585994094_1.229", "SigninToken": "svX6LGcBbWLExKD5hcwdLu6RsLQbv36fWZN36WhxkTXpTcDpmzs2K6X8uFvCqGsBTU4KWJMffYz2rAVbdJXHMECgUfyzS869wh2DBdFEQo3e2fJgZ5YtcMSVnoX7pterS2f7926jFvdBXVFEF54JkUCMrDAutNRv1u7ZReC7v8oQoG5UmjJBbHUyvLTn5UDDvDfNowMVyRskrZRFUKT2qA**********" }
将返回的登录Token拼接到准备好的链接中,生成免登录访问链接。
http://signin.aliyun.com/federation?Action=Login &LoginUrl=<登录失效跳转的地址,一般配置为自建Web配置302跳转的URL。需要使用encodeURL对LoginUrl进行转码。> &Destination=<实际访问的OpenSearch-LLM智能问答版问答测试页面。如果有参数,则需要使用encodeURL对参数进行转码。> &SigninToken=<获取的登录Token,需要使用encodeURL对Token进行转码。>
嵌入页面
以iframe方式将链接嵌入到其他Web页面。
此处测试即为首次在浏览器中打开免登录链接,测试完成后,登录Token会失效,您需要重新生成免登录链接。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>问答测试页面链接分享</title>
</head>
<body>
<iframe width="1280" height="720" src="免登录访问链接"> </iframe>
</body>
</html>
代码示例
您可以参考以下代码示例生成问答测试页面免登录链接。
添加依赖
Java代码的Maven依赖如下:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>sts20150401</artifactId>
<version>1.1.6</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea-openapi</artifactId>
<version>0.3.7</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.23</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
生成免登录链接
运行以下代码生成免登录链接:
package com.aliyun.sample;
import com.aliyun.tea.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import java.net.URLEncoder;
import static java.lang.System.exit;
public class Sample {
/**
* <b>description</b> :
* <p>使用AK&SK初始化账号Client</p>
* @return Client
*
* @throws Exception
*/
public static com.aliyun.sts20150401.Client createClient() throws Exception {
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。建议使用更安全的 STS 方式,以下代码示例仅供参考。
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
// Endpoint 请参考 https://api.aliyun.com/product/Sts
config.endpoint = "sts.cn-hangzhou.aliyuncs.com";
return new com.aliyun.sts20150401.Client(config);
}
public static void main(String[] args_) throws Exception {
//请填入提前准备的问答测试页面Destination地址
String DestinationUrl = "";
//登录失效跳转的地址,一般配置为自建Web配置302跳转的URL。
String LoginUrl = "";
//请填入RAM角色的ARN
String RoleArn = "";
//请填入RAM角色会话名称
String RoleSessionName = "";
java.util.List<String> args = java.util.Arrays.asList(args_);
com.aliyun.sts20150401.Client client = Sample.createClient();
com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest()
.setRoleArn(RoleArn)
.setRoleSessionName(RoleSessionName);
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
try {
com.aliyun.sts20150401.models.AssumeRoleResponseBody resp = client.assumeRoleWithOptions(assumeRoleRequest, runtime).getBody();
//获取所需字段
String accessKeyId = resp.getCredentials().getAccessKeyId();
String accessKeySecret = resp.getCredentials().getAccessKeySecret();
String securityToken = resp.getCredentials().getSecurityToken();
//调用RAM单点登录SSO,获取登录Token。
String signInTokenUrl = "http://signin.aliyun.com" + String.format(
"/federation?Action=GetSigninToken"
+ "&AccessKeyId=%s"
+ "&AccessKeySecret=%s"
+ "&SecurityToken=%s&TicketType=mini",
URLEncoder.encode(accessKeyId, "utf-8"),
URLEncoder.encode(accessKeySecret, "utf-8"),
URLEncoder.encode(securityToken, "utf-8")
);
//System.out.println(signInTokenUrl);
HttpGet signInGet = new HttpGet(signInTokenUrl);
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpResponse httpResponse = httpClient.execute(signInGet);
String signInToken = "";
if (httpResponse.getStatusLine().getStatusCode() == 200) {
String signInRes = EntityUtils.toString(httpResponse.getEntity());
//System.out.println(signInRes);
signInToken = JSON.parseObject(signInRes).getString("SigninToken");
if (signInToken == null) {
System.out.println("Invalid response message, contains no SigninToken: " + signInRes);
exit(-1);
}
} else {
System.out.println("Failed to retrieve signInToken");
exit(-1);
}
//将返回的登录Token拼接到准备好的链接中,生成免登录访问链接。
String signInUrl = "http://signin.aliyun.com" + String.format(
"/federation?Action=Login"
+ "&LoginUrl=%s"
+ "&Destination=%s"
+ "&SigninToken=%s",
URLEncoder.encode(LoginUrl, "utf-8"),
URLEncoder.encode(DestinationUrl, "utf-8"),
URLEncoder.encode(signInToken, "utf-8"));
//最终生成的问答测试分享链接
System.out.println(signInUrl);
} catch (TeaException error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
System.out.println(error.getMessage());
// 诊断地址
System.out.println(error.getData().get("Recommend"));
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
}