php 接入扣子(coze)获取 Oauth Access Token
【代码】php 接入扣子(coze)获取 Oauth Access Token。
·
在扣子官网文档里没有提供php版sdk,以下代码实现获取Oauth Access Token。
<?php
class CozeLogic
{
public function get_access_token()
{
$apiUrl = "https://api.coze.cn/api/permission/oauth2/token";
$postData = [
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', // 固定值
'duration_seconds' => 86399, // 申请的 AccessToken 有效期,单位为秒,默认 900 秒,即 15 分钟。最大可设置为 86399 秒,即 24 小时。
];
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->get_jwt()
];
$response = $this->httpRequest($apiUrl, 'POST', json_encode($postData, JSON_UNESCAPED_UNICODE), $headers, 300);
$result = json_decode($response, true);
if (!empty($result['access_token'])) {
return [
'code' => 1,
'access_token' => $result['access_token'],
];
}
return [
'code' => 0,
'msg' => empty($result['error_message']) ? "获取访问令牌失败" : "获取访问令牌失败,错误码: {$result['error_code']},错误信息: {$result['error_message']}",
];
}
public function get_jwt()
{
// OAuth 应用的公钥指纹
$public_key_id = 'OAuth 应用的公钥指纹';
// OAuth 应用的 ID,必须是字符串类型
$app_id = '应用的ID';
// Header 参数
$header = [
'alg' => 'RS256', // 固定为RS256
'typ' => 'JWT', // 固定为 JWT
'kid' => strval($public_key_id) // OAuth 应用的公钥指纹
];
/**
* 访问令牌的会话标识。目前仅限在会话隔离场景下使用,即将 session_name 指定为用户在业务侧的 UID,以此区分不同业务侧用户的对话历史。
* 若未指定 session_name,不同用户的对话历史可能会掺杂在一起。
*/
$session_name = empty($_COOKIE['coze_session_name']) ? '' : $_COOKIE['coze_session_name'];
if (empty($session_name)) {
$session_name = 'coze_' . strval(session('users_id')); // 根据业务改成等于用户的uid
}
if (empty($session_name)) {
$session_name = session_id();
}
setcookie('coze_session_name', $session_name);
// Payload 参数
$payload = [
'iss' => strval($app_id), // OAuth 应用的 ID
'aud' => 'api.coze.cn', //扣子 API 的Endpoint
'iat' => time(), // JWT开始生效的时间,秒级时间戳
'exp' => time() + 86400, // JWT过期时间,秒级时间戳
'jti' => (string) $this->get_rand_str(48, 0, 0), // 随机字符串,防止重放攻击
'session_name' => strval($session_name), // 必须是字符串类型
];
$encodedHeader = $this->base64url_encode(json_encode($header));
$encodedPayload = $this->base64url_encode(json_encode($payload));
$signature = '';
$data = $encodedHeader . '.' . $encodedPayload;
// 私钥,改成自己的私钥
$private_key = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCY7GRpdboUXUV3\ntmuGjvx0P8GeoMaU1ybW/ipHKA1QMmkIXOWjS+c4p6e/VCRQXCETsLgzzvkGPtMd\nfeJkFlegXf/OcgGiqZZwZENc2pgFhqAyJtuP6AVgEEwMzrStZy/L8/HiBN+qQSL/\ntd+wuPIk5kqCHTkpJB2Of4awEe7yZHLqSAiHVjSWH3RVos6ftq140XFDlSF32B0C\noSQzrizvxA2XTRgvoZJoofX29eCXtKAP/ERdsUfjpR2synEWpBu0Hq/XZ/WSBz6O\nBPXRxBuTFDdeNFYfmNIjWDCFj/V5IwvsGNGm9uIPqYlRWo14CO3jrI07EzkEJ2L4\nYJ35GlAJAgMBAAECggEAAXbZy/xp61emMNwU+dejZ76nCglTawz62Boceaxl+tYH\niHvkO1ATuK8Hrz0wSlOX6C/iYAufE1rCMhd4tbLhkXcCjXcs8eIcEmHHyj5lFrN0\n7ZObhiYBEpJuLTBRZx70cUhgRFGxE98jC8eehFTAnwIUZbXMLIsy6PPQ/51YvrOP\nLDoo/cr+PFhDDh+shpoSIxHaKvBlGsgbcvOkCmZukMRamD9gE/gtiBHrIrNzVbam\nF9DopX8BJdTMJt13R952LT9+bdsh57F1ufW3JCp0m0x9gL0NisPARqQr4MuYByWX\nBDWpCQuk4SjQIug3YE5kdqLMBZRsv5Zb+gIchX7lUQKBgQDXn7h1aMkVVJ7EfmBV\nkLpNMWrXV3Qd/1Afsa5xUVUcgdmGN3wokGZFxLXSysXpqKW5kFygsI5EUttUWHWs\nMqmyvpHYSzUcmM84PubLqZM3wNGUSs7mds8otFJ+/ZIy/e7o8DQbb6T/hb1hvlhK\nB76IQF08H/d+t/FQXSVO5UaT8QKBgQC1jwWrT0RcxQ7T2TS5oHZ9p8DTLpbfmdsl\n7zJc3wjId5OhWZtsNm/FlBqkQtL86jCa0UEHvBZ7at78iE6hkWwJWgprPIqStrdz\nW1RCNqJAJjfTWvgSfHTVBCkLd7R7aN6AjERRPuK1NCS4BZS+0II3nADVfE3iVU4v\n6Rq4yPs1mQKBgHYXhtnewsqI5s9s+2vBcRdX6lD4F6NaMlK5aHWterS7NRw6BSje\nNPUfEAnbfltDP0iLFP/40mH/Exp1vDTMJn67unrAbd00n8EJSjPesr9FPkM+WWSF\nS13arJfaXpjI1HEFJTSlh7NeVuNScV5SMXrD7YxBYbYoHeTKruUv0uCxAoGAGON6\nS3maTX1WAwSLjcbJd4A/lrOUSyK0QAcCSGjqs1BxFHVMMRFlURh0boAanEEeWJrG\n52CJVHHaD5Q/8zYUMVP+iaTK+kHB9DZY3prOsyyKCpc12pLlES540fGe9Cv0FHsm\nAl00htKXFgLt2RqMP0NLefiIVLaM+VRjLWGfzkECgYBhUsvJjmQFDN/7I9o162EF\ny2sXOpMiwiMJbqs564nbYPlY0v/T2dXaGJiLp42Dm07RiY13uy1tfLKWhd5d/7Sl\nZDtSqT6i5EsEkobfyDL8TWilo3SFkEMev2OemkgP10wq+qOA1W81AiuFZb8bNVyp\nyDLlkHBdofoPtXWzKtBZGQ==\n-----END PRIVATE KEY-----";
openssl_sign($data, $signature, $private_key, 'sha256WithRSAEncryption');
$encodeSignature = $this->base64url_encode($signature);
return $encodedHeader . '.' . $encodedPayload . '.' . $encodeSignature;
}
private function base64url_encode($data)
{
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
/**
* 获取随机字符串
* @param int $randLength 长度
* @param int $addtime 是否加入当前时间戳
* @param int $includenumber 是否包含数字
* @return string
*/
private function get_rand_str($randLength = 6, $addtime = 1, $includenumber = 0)
{
if (1 == $includenumber) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789';
} else if (2 == $includenumber) {
$chars = '123456789';
} else if (3 == $includenumber) {
$chars = 'ABCDEFGHJKLMNPQEST123456789';
} else {
$chars = 'abcdefghijklmnopqrstuvwxyz';
}
$len = strlen($chars);
$randStr = '';
for ($i = 0; $i < $randLength; $i++) {
$randStr .= $chars[rand(0, $len - 1)];
}
$tokenvalue = $randStr;
if ($addtime) {
$tokenvalue = $randStr . time();
}
return $tokenvalue;
}
/**
* CURL请求
*
* @param $url 请求url地址
* @param $method 请求方法 get post
* @param null $postfields post数据数组
* @param array $headers 请求header信息
* @param bool|false $debug 调试开启 默认false
* @return mixed
*/
private function httpRequest($url, $method = "GET", $postfields = null, $headers = array(), $timeout = 30, $debug = false)
{
$method = strtoupper($method);
$ci = curl_init();
/* Curl settings */
// curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); // 使用哪个版本
curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
// curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
curl_setopt($ci, CURLOPT_TIMEOUT, $timeout); /* 设置cURL允许执行的最长秒数 */
curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
switch ($method) {
case "POST":
curl_setopt($ci, CURLOPT_POST, true);
if (!empty($postfields)) {
if (is_string($postfields) && preg_match('/^([\w\-]+=[\w\-]+(&[\w\-]+=[\w\-]+)*)$/', $postfields)) {
parse_str($postfields, $output);
$postfields = $output;
}
if (is_array($postfields)) {
$tmpdatastr = http_build_query($postfields);
} else {
$tmpdatastr = $postfields;
}
curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
}
break;
default:
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
break;
}
$ssl = preg_match('/^https:\/\//i', $url) ? TRUE : FALSE;
curl_setopt($ci, CURLOPT_URL, $url);
if ($ssl) {
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
// curl_setopt($ci, CURLOPT_SSLVERSION, 4); //因为之前的POODLE 病毒爆发,许多网站禁用了sslv3(nginx默认是禁用的,ssl_protocols 默认值为TLSv1 TLSv1.1 TLSv1.2;),最新使用sslv4
}
//curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {
curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
}
curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ci, CURLINFO_HEADER_OUT, true);
/*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
$response = curl_exec($ci);
$requestinfo = curl_getinfo($ci);
$http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
if ($debug) {
echo "=====post data======\r\n";
var_dump($postfields);
echo "=====info===== \r\n";
print_r($requestinfo);
echo "=====response=====\r\n";
print_r($response);
}
curl_close($ci);
return $response;
//return array($http_code, $response,$requestinfo);
}
}
扣子chat sdk 在网页前端的代码实现:
<!DOCTYPE html>
<html>
<head>
<title>扣子智能客服</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<script src="https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.1.0-beta.3/libs/cn/index.js"></script>
<script>
var botId = "Agent ID";
var access_token = "access_token值";
const cozeWebSDK = new CozeWebSDK.WebChatClient({
config: {
// Agent ID
botId: botId,
},
// componentProps: {
// title: '智能客服',
// },
auth: {
// Authentication methods, the default type is 'unauth', which means no authentication is required; it is recommended to set it to 'token', indicating authentication through PAT (Personal Access Token) or OAuth
type: 'token',
// When the type is set to 'token', it is necessary to configure a PAT (Personal Access Token) or OAuth access token for authentication.
token: access_token,
// When the access token expires, use a new token and set it as needed.
onRefreshToken: async () => {
$.ajax({
type : 'get',
url : "这里填写获取access token的url",
data : {_ajax:1},
dataType : 'json',
success : function(res){
if (res.code == 1) {
return res.data.access_token;
}else{
console.log(res.msg);
}
},
error: function(e){
console.log(e.responseText);
}
});
},
},
// userInfo: {
// url: '用户头像',
// nickname: "用户名或昵称",
// id: "用户id",
// },
ui: {
base: {
// icon: '自定义图标',
// layout: 'pc',
// lang: 'zh-CN',
zIndex: 1000,
},
header: {
isShow: true,
isNeedClose: true,
},
asstBtn: {
isNeed: true, // 悬浮球的显示与隐藏
},
footer: {
isShow: true,
expressionText: 'Powered by © {{name}} {{name1}} 版权所有',
linkvars: {
name: {
text: '2016-2024',
},
name1: {
text: 'coze',
link: 'https://www.coze.cn'
}
}
},
chatBot: {
title: "智能客服",
uploadable: true,
width: 460, // PC 端窗口的宽度,单位为 px,默认为 460。
el: undefined,
// el: document.getElementById('position_demo'),
onHide: () => { // 当聊天框隐藏的时候,会回调该方法。
console.log('onHide')
// todo...
},
onShow: () => { // 当聊天框显示的时候,会回调该方法。
console.log('onShow')
// todo...
},
onBeforeShow: () => { // 聊天框显示前调用,如果返回了 false,则不会显示。支持异步函数。
// return false;
console.log('onBeforeShow')
// todo...
},
onBeforeHide: () => { // 聊天框隐藏前调用,如果返回了 false,则不会隐藏。支持异步函数。
// return false;
console.log('onBeforeHide')
// todo...
},
},
},
});
</script>
</body>
</html>
更多推荐
所有评论(0)