存客宝应用接口初始化
This commit is contained in:
255
application/common/service/AuthService.php
Normal file
255
application/common/service/AuthService.php
Normal file
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\model\User as UserModel;
|
||||
use app\common\util\JwtUtil;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Env;
|
||||
use think\facade\Log;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
const TOKEN_EXPIRE = 86400 * 365;
|
||||
|
||||
protected $smsService;
|
||||
|
||||
/**
|
||||
* 获取用户基本信息
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $typeId
|
||||
* @return UserModel
|
||||
*/
|
||||
protected function getUserProfileWithAccountAndType(string $account, int $typeId): UserModel
|
||||
{
|
||||
$user = UserModel::where(function ($query) use ($account) {
|
||||
$query->where('phone', $account)->whereOr('account', $account);
|
||||
})
|
||||
->where(function ($query) use ($typeId) {
|
||||
$query->where('status', 1)->where('typeId', $typeId);
|
||||
})->find();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @param string $account 账号(手机号)
|
||||
* @param string $password 密码(可能是加密后的)
|
||||
* @param int $typeId 身份信息
|
||||
* @return array|null
|
||||
*/
|
||||
protected function getUser(string $account, string $password, int $typeId): array
|
||||
{
|
||||
$user = $this->getUserProfileWithAccountAndType($account, $typeId);
|
||||
|
||||
if (!$user) {
|
||||
throw new \Exception('用户不存在或已禁用', 403);
|
||||
}
|
||||
|
||||
if ($user->passwordMd5 !== md5($password)) {
|
||||
throw new \Exception('账号或密码错误', 403);
|
||||
}
|
||||
|
||||
return $user->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->smsService = new SmsService();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*
|
||||
* @param string $account 账号(手机号)
|
||||
* @param string $password 密码(可能是加密后的)
|
||||
* @param string $ip 登录IP
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function login(string $account, string $password, int $typeId, string $ip)
|
||||
{
|
||||
// 获取用户信息
|
||||
$member = $this->getUser($account, $password, $typeId);
|
||||
|
||||
// 生成JWT令牌
|
||||
$token = JwtUtil::createToken($user, self::TOKEN_EXPIRE);
|
||||
$token_expired = time() + self::TOKEN_EXPIRE;
|
||||
|
||||
return compact('member', 'token', 'token_expired');
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号验证码登录
|
||||
*
|
||||
* @param string $account 手机号
|
||||
* @param string $code 验证码(可能是加密后的)
|
||||
* @param string $ip 登录IP
|
||||
* @param bool $isEncrypted 验证码是否已加密
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function mobileLogin($account, $code, $ip, $isEncrypted = false)
|
||||
{
|
||||
// 验证验证码
|
||||
if (!$this->smsService->verifyCode($account, $code, 'login', $isEncrypted)) {
|
||||
Log::info('验证码验证失败', ['account' => $account, 'ip' => $ip, 'is_encrypted' => $isEncrypted]);
|
||||
throw new \Exception('验证码错误或已过期', 404);
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
$user = User::getUserByMobile($account);
|
||||
if (empty($user)) {
|
||||
Log::info('用户不存在', ['account' => $account, 'ip' => $ip]);
|
||||
throw new \Exception('用户不存在', 404);
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
$token = JwtUtil::createToken($user, self::TOKEN_EXPIRE);
|
||||
$expireTime = time() + self::TOKEN_EXPIRE;
|
||||
|
||||
// 记录登录成功
|
||||
Log::info('手机号登录成功', ['account' => $account, 'ip' => $ip]);
|
||||
|
||||
return [
|
||||
'token' => $token,
|
||||
'token_expired' => $expireTime,
|
||||
'member' => $user
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送登录验证码
|
||||
*
|
||||
* @param string $account 手机号
|
||||
* @param string $type 验证码类型
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function sendLoginCode($account, $type)
|
||||
{
|
||||
return $this->smsService->sendCode($account, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*
|
||||
* @param array $userInfo JWT中的用户信息
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getUserInfo($userInfo)
|
||||
{
|
||||
if (empty($userInfo)) {
|
||||
throw new \Exception('获取用户信息失败');
|
||||
}
|
||||
|
||||
// 移除不需要返回的字段
|
||||
unset($userInfo['exp']);
|
||||
unset($userInfo['iat']);
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新令牌
|
||||
*
|
||||
* @param array $userInfo JWT中的用户信息
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function refreshToken($userInfo)
|
||||
{
|
||||
if (empty($userInfo)) {
|
||||
throw new \Exception('刷新令牌失败');
|
||||
}
|
||||
|
||||
// 移除过期时间信息
|
||||
unset($userInfo['exp']);
|
||||
unset($userInfo['iat']);
|
||||
|
||||
// 生成新令牌
|
||||
$token = JwtUtil::createToken($userInfo, self::TOKEN_EXPIRE);
|
||||
$expireTime = time() + self::TOKEN_EXPIRE;
|
||||
|
||||
return [
|
||||
'token' => $token,
|
||||
'token_expired' => $expireTime
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统授权信息,使用缓存存储10分钟
|
||||
*
|
||||
* @param bool $useCache 是否使用缓存
|
||||
* @return string
|
||||
*/
|
||||
public static function getSystemAuthorization($useCache = true)
|
||||
{
|
||||
// 定义缓存键名
|
||||
$cacheKey = 'system_authorization_token';
|
||||
|
||||
// 尝试从缓存获取授权信息
|
||||
$authorization = Cache::get($cacheKey);
|
||||
//$authorization = '';
|
||||
// 如果缓存中没有或已过期,则重新获取
|
||||
if (empty($authorization) || !$useCache) {
|
||||
try {
|
||||
// 从环境变量中获取API用户名和密码
|
||||
$username = Env::get('api.username', '');
|
||||
$password = Env::get('api.password', '');
|
||||
|
||||
if (empty($username) || empty($password)) {
|
||||
Log::error('缺少API用户名或密码配置');
|
||||
return '';
|
||||
}
|
||||
|
||||
// 构建登录参数
|
||||
$params = [
|
||||
'grant_type' => 'password',
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
];
|
||||
|
||||
// 获取API基础URL
|
||||
$baseUrl = Env::get('api.wechat_url', '');
|
||||
if (empty($baseUrl)) {
|
||||
Log::error('缺少API基础URL配置');
|
||||
return '';
|
||||
}
|
||||
|
||||
// 调用登录接口获取token
|
||||
// 设置请求头
|
||||
$headerData = ['client:system'];
|
||||
$header = setHeader($headerData, '', 'plain');
|
||||
$result = requestCurl($baseUrl . 'token', $params, 'POST', $header);
|
||||
$result_array = handleApiResponse($result);
|
||||
|
||||
if (isset($result_array['access_token']) && !empty($result_array['access_token'])) {
|
||||
$authorization = $result_array['access_token'];
|
||||
|
||||
// 存入缓存,有效期10分钟(600秒)
|
||||
Cache::set($cacheKey, $authorization, 600);
|
||||
Cache::set('system_refresh_token', $result_array['refresh_token'], 600);
|
||||
|
||||
Log::info('已重新获取系统授权信息并缓存');
|
||||
return $authorization;
|
||||
} else {
|
||||
Log::error('获取系统授权信息失败:' . ($response['message'] ?? '未知错误'));
|
||||
return '';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error('获取系统授权信息异常:' . $e->getMessage());
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return $authorization;
|
||||
}
|
||||
}
|
||||
82
application/common/service/ClassTableService.php
Normal file
82
application/common/service/ClassTableService.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace app\common\service;
|
||||
|
||||
use library\ClassTable;
|
||||
use think\Container;
|
||||
|
||||
class ClassTableService
|
||||
{
|
||||
protected $app;
|
||||
protected $classTable;
|
||||
|
||||
public function __construct(Container $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->classTable = ClassTable::getSelfInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定实例或类到容器
|
||||
* @param string|array $alias
|
||||
* @param mixed $instance
|
||||
* @param string|null $tag
|
||||
*/
|
||||
public function bind($alias, $instance = null, string $tag = null)
|
||||
{
|
||||
$this->classTable->bind($alias, $instance, $tag);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @param string|object $class
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function getInstance($class, ...$parameters)
|
||||
{
|
||||
return $this->classTable->getInstance($class, ...$parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取共享实例
|
||||
* @param string $alias
|
||||
* @param array $parameters
|
||||
* @return object|null
|
||||
*/
|
||||
public function getShared($alias, array $parameters = [])
|
||||
{
|
||||
return $this->classTable->getShared($alias, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据标签获取类
|
||||
* @param string $tag
|
||||
* @return array|null
|
||||
*/
|
||||
public function getClassByTag(string $tag)
|
||||
{
|
||||
return $this->classTable->getClassByTag($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查别名是否存在
|
||||
* @param string $alias
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $alias)
|
||||
{
|
||||
return $this->classTable->has($alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制实例
|
||||
* @param mixed $class
|
||||
* @param string|null $name
|
||||
* @return object
|
||||
*/
|
||||
public function copy($class, string $name = null)
|
||||
{
|
||||
return $this->classTable->copy($class, $name);
|
||||
}
|
||||
}
|
||||
203
application/common/service/SmsService.php
Normal file
203
application/common/service/SmsService.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use think\facade\Cache;
|
||||
use think\facade\Log;
|
||||
|
||||
/**
|
||||
* 短信服务类
|
||||
*/
|
||||
class SmsService
|
||||
{
|
||||
/**
|
||||
* 验证码有效期(秒)
|
||||
*/
|
||||
const CODE_EXPIRE = 300;
|
||||
|
||||
/**
|
||||
* 验证码长度
|
||||
*/
|
||||
const CODE_LENGTH = 4;
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
* @param string $mobile 手机号
|
||||
* @param string $type 验证码类型 (login, register)
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function sendCode($mobile, $type)
|
||||
{
|
||||
// 检查发送频率限制
|
||||
$this->checkSendLimit($mobile, $type);
|
||||
|
||||
// 生成验证码
|
||||
$code = $this->generateCode();
|
||||
|
||||
// 缓存验证码
|
||||
$this->saveCode($mobile, $code, $type);
|
||||
|
||||
// 发送验证码(实际项目中对接短信平台)
|
||||
$this->doSend($mobile, $code, $type);
|
||||
|
||||
// 记录日志
|
||||
Log::info('发送验证码', [
|
||||
'mobile' => $mobile,
|
||||
'type' => $type,
|
||||
'code' => $code
|
||||
]);
|
||||
|
||||
return [
|
||||
'mobile' => $mobile,
|
||||
'expire' => self::CODE_EXPIRE,
|
||||
// 测试环境返回验证码,生产环境不应返回
|
||||
'code' => $code
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证验证码
|
||||
* @param string $mobile 手机号
|
||||
* @param string $code 验证码(可能是加密后的)
|
||||
* @param string $type 验证码类型
|
||||
* @param bool $isEncrypted 验证码是否已加密
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCode($mobile, $code, $type, $isEncrypted = false)
|
||||
{
|
||||
$cacheKey = $this->getCodeCacheKey($mobile, $type);
|
||||
$cacheCode = Cache::get($cacheKey);
|
||||
|
||||
if (!$cacheCode) {
|
||||
Log::info('验证码不存在或已过期', [
|
||||
'mobile' => $mobile,
|
||||
'type' => $type
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证码是否匹配
|
||||
$isValid = false;
|
||||
|
||||
if ($isEncrypted) {
|
||||
// 前端已加密,需要对缓存中的验证码进行相同的加密处理
|
||||
$encryptedCacheCode = $this->encryptCode($cacheCode);
|
||||
$isValid = hash_equals($encryptedCacheCode, $code);
|
||||
|
||||
// 记录日志
|
||||
Log::info('加密验证码验证', [
|
||||
'mobile' => $mobile,
|
||||
'cache_code' => $cacheCode,
|
||||
'encrypted_cache_code' => $encryptedCacheCode,
|
||||
'input_code' => $code,
|
||||
'is_valid' => $isValid
|
||||
]);
|
||||
} else {
|
||||
// 未加密,直接比较
|
||||
$isValid = ($cacheCode === $code);
|
||||
|
||||
// 记录日志
|
||||
Log::info('明文验证码验证', [
|
||||
'mobile' => $mobile,
|
||||
'cache_code' => $cacheCode,
|
||||
'input_code' => $code,
|
||||
'is_valid' => $isValid
|
||||
]);
|
||||
}
|
||||
|
||||
// 验证成功后删除缓存
|
||||
if ($isValid) {
|
||||
Cache::rm($cacheKey);
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查发送频率限制
|
||||
* @param string $mobile 手机号
|
||||
* @param string $type 验证码类型
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function checkSendLimit($mobile, $type)
|
||||
{
|
||||
$cacheKey = $this->getCodeCacheKey($mobile, $type);
|
||||
|
||||
// 检查是否存在未过期的验证码
|
||||
if (Cache::has($cacheKey)) {
|
||||
throw new \Exception('验证码已发送,请稍后再试');
|
||||
}
|
||||
|
||||
// 检查当日发送次数限制
|
||||
$limitKey = "sms_limit:{$mobile}:" . date('Ymd');
|
||||
$sendCount = Cache::get($limitKey, 0);
|
||||
|
||||
if ($sendCount >= 10) {
|
||||
throw new \Exception('今日发送次数已达上限');
|
||||
}
|
||||
|
||||
// 更新发送次数
|
||||
Cache::set($limitKey, $sendCount + 1, 86400);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机验证码
|
||||
* @return string
|
||||
*/
|
||||
protected function generateCode()
|
||||
{
|
||||
// 生成4位数字验证码
|
||||
return sprintf("%0" . self::CODE_LENGTH . "d", mt_rand(0, pow(10, self::CODE_LENGTH) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存验证码到缓存
|
||||
* @param string $mobile 手机号
|
||||
* @param string $code 验证码
|
||||
* @param string $type 验证码类型
|
||||
*/
|
||||
protected function saveCode($mobile, $code, $type)
|
||||
{
|
||||
$cacheKey = $this->getCodeCacheKey($mobile, $type);
|
||||
Cache::set($cacheKey, $code, self::CODE_EXPIRE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行发送验证码
|
||||
* @param string $mobile 手机号
|
||||
* @param string $code 验证码
|
||||
* @param string $type 验证码类型
|
||||
* @return bool
|
||||
*/
|
||||
protected function doSend($mobile, $code, $type)
|
||||
{
|
||||
// 实际项目中对接短信平台API
|
||||
// 这里仅做模拟,返回成功
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码缓存键名
|
||||
* @param string $mobile 手机号
|
||||
* @param string $type 验证码类型
|
||||
* @return string
|
||||
*/
|
||||
protected function getCodeCacheKey($mobile, $type)
|
||||
{
|
||||
return "sms_code:{$mobile}:{$type}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密验证码
|
||||
* 使用与前端相同的加密算法
|
||||
* @param string $code 原始验证码
|
||||
* @return string 加密后的验证码
|
||||
*/
|
||||
protected function encryptCode($code)
|
||||
{
|
||||
// 使用与前端相同的加密算法
|
||||
$salt = 'yishi_salt_2024'; // 与前端相同的盐值
|
||||
return hash('sha256', $code . $salt);
|
||||
}
|
||||
}
|
||||
1506
application/common/service/WechatAccountHealthScoreService.php
Normal file
1506
application/common/service/WechatAccountHealthScoreService.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user