first push
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\utils;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use support\Cache;
|
||||
use Webman\Exception\BusinessException;
|
||||
|
||||
class Feishu
|
||||
{
|
||||
|
||||
protected $appId = '';
|
||||
protected $appSecret = '';
|
||||
protected $baseUri = '';
|
||||
protected $client = null;
|
||||
protected $options = [];
|
||||
protected $error = '';
|
||||
protected $gs = 'hesu';
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*/
|
||||
public function __construct(string $appId = '', string $appSecret = '', string $gs = 'hesu')
|
||||
{
|
||||
|
||||
if ($gs === 'mbaf') {
|
||||
$this->baseUri = 'https://open.larksuite.com/open-apis/';
|
||||
} else {
|
||||
$this->baseUri = 'https://open.feishu.cn/open-apis/';
|
||||
}
|
||||
|
||||
$this->appId = $appId;
|
||||
$this->appSecret = $appSecret;
|
||||
$this->gs = $gs;
|
||||
|
||||
$this->client = new Client([
|
||||
'base_uri' => $this->baseUri
|
||||
]);
|
||||
|
||||
$this->options = [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json; charset=utf-8'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常
|
||||
*/
|
||||
public function error()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求
|
||||
*/
|
||||
public function requestResult($url = "", $method = "POST")
|
||||
{
|
||||
try {
|
||||
$res = $this->client->request($method, $this->baseUri.$url, $this->options);
|
||||
if ($res->getBody()) {
|
||||
$result = json_decode($res->getBody(), true);
|
||||
// var_dump($result);
|
||||
if ($result["code"] === 0) {
|
||||
return $result;
|
||||
} else {
|
||||
$this->error = $result["msg"];
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->error = "result error";
|
||||
return false;
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
if ($e->hasResponse()) {
|
||||
var_dump('2 :'.$e->getResponse()->getBody());
|
||||
throw new BusinessException($e->getResponse()->getBody());
|
||||
} else {
|
||||
var_dump('3 :'.$e->getMessage());
|
||||
throw new BusinessException($e->getMessage());
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
var_dump('4 :'.$th->getFile()."|".$th->getLine()."|".$th->getMessage());
|
||||
$this->error = $th->getFile()."|".$th->getLine()."|".$th->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
public function authorize($certificate, $url = 'authen/v1/authorize')
|
||||
{
|
||||
$arr = [
|
||||
'app_id' => $certificate['appId'],
|
||||
'redirect_uri' => $certificate['rUrl'],
|
||||
'scope' => $certificate['scope'],
|
||||
'state' => $certificate['state']
|
||||
];
|
||||
$queryData = http_build_query($arr);
|
||||
return $this->baseUri.$url.'?'.$queryData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自建应用获取 tenant_access_token
|
||||
*/
|
||||
public function tenantAccessToken()
|
||||
{
|
||||
$tenantAccessToken = Cache::get($this->gs.'-tenantAccessToken');
|
||||
if (!$tenantAccessToken) {
|
||||
$this->options["json"] = [
|
||||
"app_id" => $this->appId,
|
||||
"app_secret" => $this->appSecret
|
||||
];
|
||||
$rst = $this->requestResult('auth/v3/tenant_access_token/internal', 'POST');
|
||||
if ($rst) {
|
||||
$tenantAccessToken = $rst['tenant_access_token'];
|
||||
Cache::set($this->gs.'-tenantAccessToken', $tenantAccessToken, $rst['expire']);
|
||||
} else {
|
||||
throw new BusinessException('tenant_access_token 获取失败');
|
||||
}
|
||||
}
|
||||
return $tenantAccessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过手机号或邮箱获取用户 ID
|
||||
*/
|
||||
public function getUserIdByPhoneOrEmail($phone = '', $userIdType = 'open_id')
|
||||
{
|
||||
$this->options["headers"] = [
|
||||
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||
"Content-Type" => "application/json; charset=utf-8"
|
||||
];
|
||||
$this->options["json"] = [
|
||||
"emails" => [],
|
||||
"mobiles" => [$phone],
|
||||
"include_resigned" => false
|
||||
];
|
||||
$rst = $this->requestResult('contact/v3/users/batch_get_id?user_id_type='.$userIdType, 'POST');
|
||||
return $rst;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*/
|
||||
public function sendMessages($receiveId = '', $content = '', $msgType = 'text', $receiveIdtype = 'open_id')
|
||||
{
|
||||
$this->options["headers"] = [
|
||||
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||
"Content-Type" => "application/json; charset=utf-8"
|
||||
];
|
||||
$this->options["json"] = [
|
||||
"receive_id" => $receiveId,
|
||||
"msg_type" => $msgType,
|
||||
"content" => $content
|
||||
];
|
||||
$rst = $this->requestResult('im/v1/messages?receive_id_type='.$receiveIdtype, 'POST');
|
||||
return $rst;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑消息
|
||||
*/
|
||||
public function updateSendMessages($messageId = '', $content = '', $msgType = 'text')
|
||||
{
|
||||
$this->options["headers"] = [
|
||||
"Authorization" => "Bearer " . $this->tenantAccessToken(),
|
||||
"Content-Type" => "application/json; charset=utf-8"
|
||||
];
|
||||
$this->options["json"] = [
|
||||
"msg_type" => $msgType,
|
||||
"content" => $content
|
||||
];
|
||||
$rst = $this->requestResult('im/v1/messages/'.$messageId, 'PUT');
|
||||
return $rst;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户 user_access_token
|
||||
*/
|
||||
public function userAccessToken($code = "", $redirect_uri = "")
|
||||
{
|
||||
$this->options["headers"] = [
|
||||
"Content-Type" => "application/json; charset=utf-8"
|
||||
];
|
||||
$this->options["json"] = [
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->appId,
|
||||
"client_secret" => $this->appSecret,
|
||||
"code" => $code,
|
||||
"redirect_uri" => $redirect_uri
|
||||
];
|
||||
return $this->requestResult('authen/v2/oauth/token');
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
public function userInfo($userAccessToken = "")
|
||||
{
|
||||
$this->options["headers"] = [
|
||||
"Authorization" => "Bearer " . $userAccessToken,
|
||||
"Content-Type" => "application/json; charset=utf-8"
|
||||
];
|
||||
return $this->requestResult('authen/v1/user_info', "GET");
|
||||
}
|
||||
|
||||
// public function user_access_token($code = "")
|
||||
// {
|
||||
// $url = "";
|
||||
// $this->options["headers"] = [
|
||||
// "Authorization" => "Bearer ".$this->tenantAccessToken(),
|
||||
// "Content-Type" => "application/json; charset=utf-8"
|
||||
// ];
|
||||
// $this->options["json"] = [
|
||||
// "grant_type" => "authorization_code",
|
||||
// "code" => $code
|
||||
// ];
|
||||
// $this->options["form_params"] = [
|
||||
// "app_id" => $this->app_id,
|
||||
// "app_secret" => $this->app_secret
|
||||
// ];
|
||||
// return $this->requestResult($url);
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\utils;
|
||||
|
||||
use Firebase\JWT\JWT as FirebaseJWT;
|
||||
use Firebase\JWT\Key;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
class Jwt
|
||||
{
|
||||
protected $secretKey;
|
||||
protected $algorithm;
|
||||
protected $issuer;
|
||||
protected $expiration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->secretKey = config('jwt.jwt_secret_key');
|
||||
$this->algorithm = config('jwt.jwt_algorithm');
|
||||
$this->issuer = config('jwt.jwt_issuer');
|
||||
$this->expiration = config('jwt.jwt_expiration');
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JWT 令牌
|
||||
*
|
||||
* @param array $payload
|
||||
* @return string
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function generateToken(array $payload): string
|
||||
{
|
||||
$defaultPayload = [
|
||||
// // —— 注册 Claim ——
|
||||
'iss' => $this->issuer, // 签发者
|
||||
// 'sub' => 'user_1001', // 面向的用户
|
||||
// 'aud' => 'api.gateway.example.com', // 接收方
|
||||
// 'iat' => time(), // 签发时间
|
||||
// 'nbf' => time(), // 生效时间
|
||||
// 'exp' => time() + $this->expiration, // 1 小时后过期
|
||||
'jti' => bin2hex(random_bytes(16)), // 唯一 ID
|
||||
// // —— 自定义 Claim ——
|
||||
// 'uid' => 1001, // 业务用户 ID
|
||||
// 'roles' => ['admin', 'editor'], // 用户角色
|
||||
// 'meta' => ['region' => 'CN', 'tier' => 5], // 任意自定义数据
|
||||
];
|
||||
|
||||
$payload = array_merge($defaultPayload, $payload);
|
||||
|
||||
try {
|
||||
return FirebaseJWT::encode($payload, $this->secretKey, $this->algorithm);
|
||||
} catch (\Exception $e) {
|
||||
throw new BusinessException("令牌生成失败:" . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 JWT 令牌
|
||||
*
|
||||
* @param string $token
|
||||
* @return object
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function verifyToken(string $token)
|
||||
{
|
||||
try {
|
||||
return FirebaseJWT::decode($token, new Key($this->secretKey, $this->algorithm));
|
||||
} catch (\Firebase\JWT\ExpiredException $e) {
|
||||
throw new BusinessException('令牌已过期', 401);
|
||||
} catch (\Firebase\JWT\SignatureInvalidException $e) {
|
||||
throw new BusinessException('无效的令牌签名', 401);
|
||||
} catch (\Firebase\JWT\BeforeValidException $e) {
|
||||
throw new BusinessException('令牌尚未生效', 401);
|
||||
} catch (\Exception $e) {
|
||||
throw new BusinessException('令牌验证失败:' . $e->getMessage(), 400);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function describe()
|
||||
{
|
||||
/* payload
|
||||
1. 注册 Claim 详解
|
||||
|
||||
Claim 名称 含义 类型 建议取值
|
||||
iss Issuer,发行者,标识该 JWT 的签发主体 string or URI 你的服务域名或项目标识,比如 https://api.example.com
|
||||
sub Subject,主题,标识该 JWT 所面向的用户 string or int 用户在你系统里的唯一 ID
|
||||
aud Audience,受众,标识该 JWT 的接收方 string or array 接收该令牌的服务标识,比如 ["service-a","service-b"]
|
||||
exp Expiration Time,过期时间,Unix 时间戳,到达此时间后不可用 int time() + 3600(1 小时后过期)
|
||||
nbf Not Before,生效时间,Unix 时间戳,表示在此时间之前不可用 int time() 或者 time() + 60(1 分钟后生效)
|
||||
iat Issued At,签发时间,Unix 时间戳 int time()
|
||||
jti JWT ID,JWT 的唯一标识符,用于去重或一次性令牌 string uniqid('', true) 或者 UUID
|
||||
|
||||
注意:exp、nbf、iat 必须是整数(秒级时间戳),否则库会抛类型异常或验证失败。
|
||||
|
||||
2. 自定义 Claim
|
||||
|
||||
除了上面这些“注册”字段,你可以任意添加,比如:
|
||||
|
||||
php
|
||||
$payload['uid'] = 123; // 业务用户 ID
|
||||
$payload['roles'] = ['admin','user']; // 权限数组
|
||||
$payload['feature'] = 'beta'; // 标记某个功能开关
|
||||
|
||||
这些字段在你的应用程序里可以自由取用。
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\utils;
|
||||
|
||||
class OauthClients
|
||||
{
|
||||
|
||||
/**
|
||||
* 生成 OAuth2 client 凭证
|
||||
*
|
||||
* @param int $idBytes 用于生成 client_id 的随机字节长度(最终 hex 长度 = $idBytes * 2)
|
||||
* @param int $secretBytes 用于生成 client_secret 的随机字节长度(最终 hex 长度 = $secretBytes * 2)
|
||||
* @return array ['client_id' => string, 'client_secret' => string]
|
||||
*/
|
||||
public function generateClientCredentials(int $idBytes = 16, int $secretBytes = 32): array
|
||||
{
|
||||
// 生成随机字节,并转为十六进制字符串
|
||||
$clientId = bin2hex(random_bytes($idBytes));
|
||||
$clientSecret = bin2hex(random_bytes($secretBytes));
|
||||
|
||||
return [
|
||||
'client_id' => $clientId,
|
||||
'client_secret' => $clientSecret,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user