Files
miniapi/app/miniapi/controller/Auth.php
gaofeng 4320b80426 提交
2026-06-17 16:56:29 +08:00

185 lines
5.6 KiB
PHP

<?php
declare (strict_types=1);
namespace app\miniapi\controller;
use api\Httpcurl;
use app\service\MiniProgramWechatService;
use think\exception\ValidateException;
use think\facade\Cache;
class Auth extends Base
{
public function sendSms()
{
$data = $this->postData();
if ($error = $this->requireFields($data, ['mobile'])) {
return $error;
}
$mobile = trim((string)$data['mobile']);
$smsUrl = $this->smsUrl();
if ($smsUrl === '') {
return $this->fail('短信验证码接口未配置');
}
$code = mt_rand(1001, 9999);
$siteDomain = $this->currentSiteDomain();
$response = Httpcurl::request($smsUrl, 'post', [
'mobile' => $mobile,
'code' => $code,
'model' => MODEL,
'mini_app_code' => $this->currentMiniAppCode(),
'company_code' => $this->currentCompanyCode(),
'domain' => $siteDomain,
'site_domain' => $siteDomain,
], $this->smsHeaders($siteDomain));
$result = $this->decodeResponse($response, 'miniapi send sms');
if (empty($result) || intval($result['code'] ?? 0) !== 1) {
return $this->fail('发送验证码失败');
}
Cache::set($this->smsCacheKey($mobile), $code . '|' . time(), 300);
return $this->ok([], '发送成功');
}
public function login()
{
$data = $this->postData();
try {
$this->validate($data, [
'mobile' => 'require',
'code' => 'require',
], [
'mobile.require' => '手机号不能为空',
'code.require' => '验证码不能为空',
]);
} catch (ValidateException $e) {
return $this->fail($e->getError());
}
$mobile = trim((string)$data['mobile']);
$code = trim((string)$data['code']);
$cacheKey = $this->smsCacheKey($mobile);
$cached = (string)Cache::get($cacheKey, '');
if ($cached === '') {
return $this->fail('验证码已失效,请重新发送');
}
$parts = explode('|', $cached, 2);
$sms = (string)($parts[0] ?? '');
$codeTime = intval($parts[1] ?? 0);
if ($sms === '' || $codeTime <= 0 || (time() - $codeTime) > 300) {
Cache::delete($cacheKey);
return $this->fail('验证码超时,请重新发送');
}
if (!hash_equals($sms, $code)) {
return $this->fail('验证码不正确');
}
Cache::delete($cacheKey);
$openid = '';
if (!empty($data['login_code'])) {
$openid = $this->wechatService()->openidByLoginCode((string)$data['login_code']);
}
return $this->loginByMobile($mobile, $openid);
}
public function wxPhoneLogin()
{
$data = $this->postData();
if ($error = $this->requireFields($data, ['phone_code', 'login_code'])) {
return $error;
}
$wechat = $this->wechatService();
$openid = $wechat->openidByLoginCode((string)$data['login_code'], true);
if ($openid === '') {
return $this->fail('微信登录失败,请使用验证码登录');
}
$mobile = $wechat->mobileByPhoneCode((string)$data['phone_code']);
if ($mobile === '') {
return $this->fail('微信手机号获取失败,请使用验证码登录');
}
return $this->loginByMobile($mobile, $openid);
}
public function me()
{
$userId = $this->currentUserId();
if ($userId <= 0) {
return $this->ok(['isLogin' => false]);
}
return $this->ok([
'isLogin' => true,
]);
}
private function loginByMobile(string $mobile, string $openid = '')
{
$response = Httpcurl::request(config('app.user_url'), 'post', [
'model' => MODEL,
'mobile' => $mobile,
]);
$result = $this->decodeResponse($response, 'miniapi login');
if (empty($result) || intval($result['code'] ?? 0) !== 1 || empty($result['data']['id'])) {
return $this->fail('账号不存在');
}
$user = $result['data'];
return $this->ok([
'token' => authcode((string)$user['id'], 'ENCODE', MINIAPI_TOKEN_KEY, MINIAPI_TOKEN_EXPIRE),
'expires_in' => MINIAPI_TOKEN_EXPIRE,
'openid' => $openid,
'user' => [
'mobile' => $user['mobile'] ?? $mobile,
'nickname' => $user['nickname'] ?? '微信用户',
],
], '登录成功');
}
private function wechatService(): MiniProgramWechatService
{
return new MiniProgramWechatService($this->currentMiniAppCode(), $this->currentMiniApp());
}
private function smsCacheKey(string $mobile): string
{
return 'miniapi_sms_code_' . md5($this->currentMiniAppCode() . '|' . $mobile);
}
private function smsUrl(): string
{
return trim((string)config('app.yzm_url'));
}
private function currentSiteDomain(): string
{
$domain = trim((string)($this->currentMiniApp()['site_domain'] ?? ''));
if (stripos($domain, 'http://') === 0 || stripos($domain, 'https://') === 0) {
$domain = (string)parse_url($domain, PHP_URL_HOST);
}
return trim(explode('/', $domain)[0]);
}
private function smsHeaders(string $siteDomain): array
{
if ($siteDomain === '') {
return [];
}
$origin = 'https://' . $siteDomain;
return [
'Origin: ' . $origin,
'Referer: ' . $origin . '/',
];
}
}