SAAS 接入
无界云剪提供了接入第三方系统用户体系的功能,实现了与第三方系统用户与登录状态的互通。
一、接入原理
- 云剪平台用户相关接口采用jwt token方式做用户身份认证
- 用户映射:将第三方的用户在云剪平台中映射生成一个对应用户
- 用户token:基于映射到云剪平台中的用户生成token,并通过url参数跳转进云剪系统(云剪平台会自动解析处理token)
- 登录状态同步:
- 第三方系统提供额外的接口用于云剪平台查询用户登录状态。
- 云剪平台中每次调用用户相关接口时,除了校验自己平台内token状态,还会额外调用第三方提供的登录状态查询接口,只有都通过才算是已登录状态。
二、接入流程
1、获取 appid 和 secret
在无界云剪平台中管理后台-应用管理,创建应用,获取应用的appid
和secret
,具体获取方法请联系平台客服微信:mantousee
。
2、获取 token
调用平台接口获取token
,其中appid
和secret
由平台提供。
注意:
- 每个userId会在云剪项目中生成一个对应的用户(已存在则更新)
- 云剪项目中用户的信息会在每次调用/api/v1/third/login接口时更新。
- 云剪项目中的
token
有效期以及用户登录状态可能和第三方系统不一致,如需保持一致,第三方应该提供额外接口用于查询用户登录状态。
参考接口文档: https://docs.apipost.net/docs/detail/40f0d78218e0000?target_id=1fb5aee
参考代码
nodejs
const crypto = require('crypto');
const axios = require('axios');
/**
* md5加密
* @param {string} str
* @returns
*/
function md5(str) {
return crypto.createHash("md5").update(str).digest("hex");
}
/**
* 获取token
* @returns {user_id:”871668385574199296“, token:"Bearer eyJh***", expires_at:1758270091116}
*/
async function getToken() {
const timestamp = Date.now();//毫秒时间戳
const appid = "";//【平台获取】应用appid
const secret = "";//【平台获取】应用密钥
const url = `https://video.h5ds.com/api/v1/third/login`;//接口地址
const sign = md5(timestamp + secret);//签名
//参数
const data = {
userId: "user_01", //【必选】业务方用户的唯一标识,建议使用用户ID
nick_name: "wtone", //【可选】昵称
mobile: "15888888889", //【可选】手机号码
email: "71999911@qq.com", //【可选】电子邮箱,比如 example@qq.com
avatar: "", //【可选】头像,应该是完整可访问的地址
gender: 0, //【可选】性别 0-女 1-男 2-其他
};
//headers
const headers = {
appid,//应用appid
sign,//【重要】签名算法
timestamp,//毫秒时间戳
};
const response = await axios.post(url, data, { headers });
//接口返回{code:0,message:"success",data:{}},code非0表示错误
if (!response.data || response.data.code !== 0) {
throw new Error(response.data.message);
}
//返回格式{user_id, token, expires_at}
return response.data.data;
}
(async () => {
const { user_id, token, expires_at } = await getToken();
console.log("user_id:", user_id, "\n token:", token, "\nexpires_at:", expires_at);
})();
java
import okhttp3.*;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Token生成工具类
*/
public class SAAS {
private static final String APP_ID = ""; // 【平台获取】应用appid
private static final String SECRET = ""; // 【平台获取】应用密钥
private static final String API_URL = "https://video.h5ds.com/api/v1/third/login"; // API接口地址
/**
* 获取Token
* @return Token字符串
* @throws Exception 请求异常或API返回错误
*/
public static String getToken() throws Exception {
// 生成时间戳
long timestamp = System.currentTimeMillis();
// 生成签名(MD5(时间戳+密钥))
String sign = md5(timestamp + SECRET);
// 初始化HTTP客户端
OkHttpClient client = new OkHttpClient();
// 构造请求体JSON
String json = "{\"userId\":\"user_01\",\"nick_name\":\"wtone\"," +
"\"mobile\":\"15888888889\",\"email\":\"71999911@qq.com\"," +
"\"avatar\":\"\",\"gender\":0}";
// 创建请求体
RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));
// 构造请求头
Request request = new Request.Builder()
.url(API_URL) // 设置API地址
.post(body) // 设置为POST请求
.addHeader("appid", APP_ID) // 添加appid头
.addHeader("sign", sign) // 添加签名头
.addHeader("timestamp", String.valueOf(timestamp)) // 添加时间戳头
.addHeader("Content-Type", "application/json") // 设置内容类型
.build();
// 执行请求并处理响应
try (Response response = client.newCall(request).execute()) {
// 检查响应状态
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
// 获取响应数据
String responseData = response.body().string();
// TODO: 根据实际API响应结构解析token
return responseData;
}
}
/**
* MD5加密方法
* @param input 输入字符串
* @return MD5哈希值
* @throws NoSuchAlgorithmException
*/
private static String md5(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
// 测试主方法
public static void main(String[] args) {
try {
String token = getToken();
System.out.println("Token: " + token);
} catch (Exception e) {
e.printStackTrace();
}
}
}
php
<?php
/**
* post请求
*/
function post($url, $data, $headers)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array_merge(['Content-Type: application/json'], $headers));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('Request failed: ' . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode != 200) {
throw new Exception('API request failed with status: ' . $httpCode);
}
$responseData = json_decode($response, true);
return $responseData;
}
/**
* 获取token
*/
function getToken()
{
$timestamp = round(microtime(true) * 1000); //毫秒时间戳
$appid = "";//【平台获取】应用appid
$secret = "";//【平台获取】应用密钥
$url = 'https://video.h5ds.com/api/v1/third/login';//接口地址
$sign = md5($timestamp . $secret);//签名
//参数
$data = [
'userId' => 'user_01', //【必选】业务方用户的唯一标识,建议使用用户ID
'nick_name' => 'wtone', //【可选】昵称
'mobile' => '15888888889', //【可选】手机号码
'email' => '71999911@qq.com', //【可选】电子邮箱,比如 example@qq.com
'avatar' => '', //【可选】头像,应该是完整可访问的地址
'gender' => 0 //【可选】性别 0-女 1-男 2-其他
];
//headers
$headers = [
'appid: ' . $appid, //应用appid
'sign: ' . $sign, //【重要】签名算法
'timestamp: ' . $timestamp //毫秒时间戳
];
$responseData = post($url, $data, $headers);
if (!$responseData || $responseData['code'] !== 0) {
throw new Exception($responseData['message'] ?? 'Unknown error');
}
return $responseData['data'];
}
// 使用示例
$tokenData = getToken();
print_r($tokenData);
3、跳转到无界云剪项目
基于上面获取到的token
,通过携带 query 参数跳转到无界云剪项目中,项目会自动解析query中的token参数并再后续的接口请求中使用该token。
<a href={`https://video.h5ds.com?token=${token}`} target="_blank" />
三、用户登录状态互通
由于第三方系统中用户登录状态和云剪项目中用户登录状态(token有效期)是完全隔离的两个信息,因此为了实现用户在第三方系统中退出登录、登录失效(过期),云剪系统用户token也自动失效退出,需要第三方系统提供额外接口用于查询用户登录状态。
1、第三方系统提供登录状态查询接口
接口地址
GET http://192.168.31.46:8080/api/v1/test/saas/userStatus?userID={userId}
参数
userID 第三方系统的用户ID(调用saas登录接口时传递的userId参数)
返回格式
{
"status": 0, //用户登录状态 0-未登录 1-已登录
}
2、云剪项目配置
云剪项目需要配置登录状态查询接口,配置方式如下: server/.env
#【saas用户登录状态校验配置】
# host.saas=http://192.168.31.46:8080/api/v1/test/saas/userStatus
四、SAAS接口
saas级别的接口可以查看和管理整个应用范围内的用户和作品信息
接口参考文档:https://docs.apipost.net/docs/detail/40f0d78218e0000?target_id=1fb5aec
接口主要对Header中sign签名参数做身份权限校验
五、用户接口
实际上我们拿到 token 之后,可以请求项目中用户相关的全部 API 接口,比如获取项目列表,删除项目,更新项目等等。具体的 API 文档购买后会提供。
参考接口文档:https://docs.apipost.net/docs/detail/40f0d78218e0000?target_id=1fb58d4
接口主要对Header中的Authorization:{token}参数做身份权限校验。
接口样例
1、获取当前用户信息
/**
* 获取当前用户信息
*/
function getCurrentUserInfo(token) {
return axios({
method: "get",
url: host + "/api/v1/user/info",
headers: {
Authorization: token,
},
}).then((res) => res.data.data);
}
// 获取当前用户信息
const userInfo = await getCurrentUserInfo(token);
2、 创建一个新的工程
获取到工程数据返回参数 res
/**
* 创建一个新的H5
*/
function createMovieData(token) {
const ndata = {
title: "未命名",
createTime: +new Date(),
updateTime: +new Date(),
poster: "",
width: 1920,
height: 1080,
background: {},
transitions: [],
cameras: [],
captions: [],
elements: [],
resouces: [],
};
return axios({
method: "post",
url: host + "/api/v1/user/apps/create",
headers: {
Authorization: token,
},
data: {
source_id: "", //来源Id
category_id: 0, //分类Id
name: ndata.title, //名称
description: ndata.title, //描述
duration: 0, //时长(毫秒)
width: ndata.width, //宽度
height: ndata.height, //高度
thumb: "", //封面图url
data: ndata,
},
}).then((res) => res.data.data);
}
// 创建视频
const res = await createMovieData(token);