829 lines
29 KiB
PHP
829 lines
29 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\admin\controller;
|
||
|
||
use app\admin\BaseController;
|
||
use think\exception\ValidateException;
|
||
use think\facade\Db;
|
||
use think\facade\Cache;
|
||
use think\response\Json;
|
||
use app\service\JwtService;
|
||
|
||
use app\model\System\AdminUser;
|
||
use app\model\System\AdminUserGroup;
|
||
use app\model\System\SystemSiteSettings;
|
||
use app\model\Tenant\Tenant;
|
||
use app\model\System\OperationLog;
|
||
|
||
class LoginController extends BaseController
|
||
{
|
||
private const SMS_CODE_TTL_SECONDS = 300; // 5分钟
|
||
private const SMS_CODE_RESEND_SECONDS = 60; // 60秒可重发
|
||
|
||
private function generateToken($userInfo): string
|
||
{
|
||
return JwtService::generateToken($userInfo);
|
||
}
|
||
|
||
private function verifyToken($token): ?array
|
||
{
|
||
return JwtService::verifyToken($token);
|
||
}
|
||
|
||
private function getSiteSettingValue(string $label): string
|
||
{
|
||
$row = SystemSiteSettings::where('label', $label)
|
||
->where('delete_time', null)
|
||
->order('id', 'asc')
|
||
->find();
|
||
return $row ? (string)$row['value'] : '';
|
||
}
|
||
|
||
private function smsCodeCacheKey(string $scene, string $tenantName, string $account, string $phone): string
|
||
{
|
||
return 'sms_code:' . md5($scene . '|' . $tenantName . '|' . $account . '|' . $phone);
|
||
}
|
||
|
||
private function smsCodeThrottleKey(string $scene, string $tenantName, string $account, string $phone): string
|
||
{
|
||
return 'sms_code_throttle:' . md5($scene . '|' . $tenantName . '|' . $account . '|' . $phone);
|
||
}
|
||
|
||
private function postJson(string $url, array $payload, array $headers): array
|
||
{
|
||
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
|
||
if ($body === false) {
|
||
return ['ok' => false, 'error' => 'json_encode failed'];
|
||
}
|
||
|
||
$context = stream_context_create([
|
||
'http' => [
|
||
'method' => 'POST',
|
||
'header' => implode("\r\n", $headers),
|
||
'content' => $body,
|
||
'timeout' => 10,
|
||
'ignore_errors' => true,
|
||
],
|
||
]);
|
||
|
||
$respBody = @file_get_contents($url, false, $context);
|
||
$status = 0;
|
||
if (!empty($http_response_header) && is_array($http_response_header)) {
|
||
foreach ($http_response_header as $line) {
|
||
if (preg_match('#^HTTP/\\S+\\s+(\\d+)#', $line, $m)) {
|
||
$status = (int)$m[1];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($respBody === false) {
|
||
$last = error_get_last();
|
||
return ['ok' => false, 'status' => $status, 'error' => (string)($last['message'] ?? 'http request failed')];
|
||
}
|
||
|
||
$decoded = json_decode((string)$respBody, true);
|
||
if (!is_array($decoded)) {
|
||
$decoded = [];
|
||
}
|
||
|
||
return [
|
||
'ok' => $status >= 200 && $status < 300,
|
||
'status' => $status,
|
||
'body' => (string)$respBody,
|
||
'json' => $decoded,
|
||
];
|
||
}
|
||
|
||
private function sendSmsCodeInternal(string $scene, string $tenantName, string $account, string $phone): Json
|
||
{
|
||
$throttleKey = $this->smsCodeThrottleKey($scene, $tenantName, $account, $phone);
|
||
if (Cache::has($throttleKey)) {
|
||
return json(['code' => 429, 'msg' => '验证码发送过于频繁,请稍后再试']);
|
||
}
|
||
|
||
$backendUrl = $this->getSiteSettingValue('backendUrl');
|
||
$apiKey = $this->getSiteSettingValue('apiKey');
|
||
if ($backendUrl === '' || $apiKey === '') {
|
||
return json(['code' => 500, 'msg' => '短信网关配置缺失,请联系管理员']);
|
||
}
|
||
|
||
$code = (string)random_int(100000, 999999);
|
||
$sceneTextMap = [
|
||
'register' => '注册',
|
||
'reset' => '找回密码',
|
||
'login' => '登录',
|
||
];
|
||
$sceneText = $sceneTextMap[$scene] ?? '验证';
|
||
$content = "【云泽网】{$sceneText}验证码:{$code},5分钟内有效。";
|
||
|
||
$enqueueUrl = rtrim($backendUrl, '/') . '/api/v1/business/outbound-tasks';
|
||
$resp = $this->postJson($enqueueUrl, [
|
||
'phone' => $phone,
|
||
'content' => $content,
|
||
], [
|
||
'X-Api-Key: ' . $apiKey,
|
||
'Content-Type: application/json; charset=utf-8',
|
||
'Accept: application/json',
|
||
]);
|
||
|
||
if (empty($resp['ok'])) {
|
||
return json([
|
||
'code' => 500,
|
||
'msg' => '验证码短信发送失败',
|
||
'detail' => [
|
||
'http_status' => $resp['status'] ?? null,
|
||
'body_preview' => isset($resp['body']) ? substr((string)$resp['body'], 0, 200) : '',
|
||
]
|
||
]);
|
||
}
|
||
|
||
$codeKey = $this->smsCodeCacheKey($scene, $tenantName, $account, $phone);
|
||
Cache::set($codeKey, $code, self::SMS_CODE_TTL_SECONDS);
|
||
Cache::set($throttleKey, 1, self::SMS_CODE_RESEND_SECONDS);
|
||
|
||
return json(['code' => 200, 'msg' => '验证码已发送']);
|
||
}
|
||
|
||
private function buildLoginSuccessResponse($user, $tenant): Json
|
||
{
|
||
$tid = (int)$tenant->id;
|
||
|
||
try {
|
||
$loginCount = isset($user['login_count']) && $user['login_count'] !== null ? (int)$user['login_count'] : 0;
|
||
AdminUser::where('id', $user['id'])->update([
|
||
'login_count' => $loginCount + 1,
|
||
'last_login_ip' => $this->request->ip(),
|
||
'last_login_time' => date('Y-m-d H:i:s')
|
||
]);
|
||
} catch (\Exception $e) {
|
||
error_log('更新登录信息失败: ' . $e->getMessage());
|
||
}
|
||
|
||
$userInfo = [
|
||
'id' => $user['id'],
|
||
'account' => $user['account'],
|
||
'name' => $user['name'],
|
||
'group_id' => $user['group_id'],
|
||
'tid' => $tid,
|
||
'tenant' => $tenant
|
||
];
|
||
|
||
if ($user['group_id']) {
|
||
$userGroup = AdminUserGroup::where('id', $user['group_id'])->find();
|
||
if ($userGroup && $userGroup->rights) {
|
||
$userInfo['rights'] = json_decode($userGroup->rights, true);
|
||
}
|
||
}
|
||
|
||
try {
|
||
$token = $this->generateToken($userInfo);
|
||
} catch (\Exception $e) {
|
||
$this->logFail('登录管理', '登录', 'Token生成失败: ' . $e->getMessage());
|
||
return json(['code' => 500, 'msg' => '登录失败,请稍后重试']);
|
||
}
|
||
|
||
try {
|
||
$cacheKey = 'admin_user_' . $user['id'] . '_' . $tid;
|
||
\think\facade\Cache::set($cacheKey, $userInfo, 86400 * 7);
|
||
} catch (\Exception $e) {
|
||
error_log('用户缓存写入失败: ' . $e->getMessage());
|
||
}
|
||
|
||
try {
|
||
$this->logSuccess('登录管理', '登录', [
|
||
'id' => $user['id'],
|
||
'tid' => $tid,
|
||
'tenant' => $tenant
|
||
], $userInfo);
|
||
} catch (\Exception $e) {
|
||
error_log('登录日志记录失败: ' . $e->getMessage());
|
||
}
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '登录成功',
|
||
'data' => [
|
||
'token' => $token,
|
||
'user' => $userInfo
|
||
]
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 登录接口
|
||
* @return Json
|
||
*/
|
||
public function login(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->param();
|
||
|
||
// 1. 先验证租户名称是否传入(新增:必须传租户名称)
|
||
try {
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128', // 匹配租户表tenant字段长度
|
||
'account|账号' => 'require|length:3,32',
|
||
'password|密码' => 'require|length:6,32'
|
||
]);
|
||
} catch (ValidateException $e) {
|
||
$this->logFail('登录管理', '登录', $e->getMessage());
|
||
return json([
|
||
'code' => 400,
|
||
'msg' => $e->getError()
|
||
]);
|
||
}
|
||
|
||
// 2. 处理账号兼容(邮箱/手机号转account)
|
||
if (isset($data['email'])) {
|
||
$data['account'] = $data['email'];
|
||
} elseif (isset($data['phone'])) {
|
||
$data['account'] = $data['phone'];
|
||
}
|
||
|
||
// 3. 查询租户ID(新增:只查正常状态的租户 status=1)
|
||
$tenant = Tenant::where('tenant_name', $data['tenant_name'])
|
||
->where('status', 1) // 过滤停用/删除的租户
|
||
->field(['id', 'tenant_name']) // 只查需要的字段,提升性能
|
||
->find(); // ThinkPHP 使用 find()
|
||
|
||
|
||
|
||
// 4. 验证租户是否存在
|
||
|
||
if (!$tenant) {
|
||
$this->logFail('登录管理', '登录', '租户不存在或已禁用,租户名称:' . $data['tenant_name']);
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '租户不存在或已禁用'
|
||
]);
|
||
}
|
||
$tid = $tenant->id;
|
||
$tenant_name = $tenant->tenant_name;
|
||
|
||
// 5. 查询用户(新增:关联租户ID,确保用户属于该租户)
|
||
$user = AdminUser::where('account', $data['account'])
|
||
->where('tid', $tid) // 核心:验证用户所属租户
|
||
->where('status', 1)
|
||
->find();
|
||
|
||
// 6. 验证用户是否存在
|
||
if (!$user) {
|
||
$this->logFail('登录管理', '登录', '账号不存在/已禁用,或不属于当前租户,账号:' . $data['account'] . ',租户:' . $tenant_name);
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '账号不存在或已禁用,或不属于当前租户'
|
||
]);
|
||
}
|
||
|
||
// 7. 验证密码
|
||
if (md5($data['password']) !== $user['password']) {
|
||
$this->logFail('登录管理', '登录', '密码错误,账号:' . $data['account'] . ',租户:' . $tenant_name);
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '密码错误'
|
||
]);
|
||
}
|
||
|
||
// 8. 更新登录次数和IP
|
||
try {
|
||
$loginCount = isset($user['login_count']) && $user['login_count'] !== null ? (int)$user['login_count'] : 0;
|
||
AdminUser::where('id', $user['id'])->update([
|
||
'login_count' => $loginCount + 1,
|
||
'last_login_ip' => $this->request->ip(),
|
||
'last_login_time' => date('Y-m-d H:i:s') // 新增:记录最后登录时间,更实用
|
||
]);
|
||
} catch (\Exception $e) {
|
||
error_log('更新登录信息失败: ' . $e->getMessage());
|
||
}
|
||
|
||
// 9. 组装用户信息(新增:加入租户ID和租户名称和角色权限)
|
||
$userInfo = [
|
||
'id' => $user['id'],
|
||
'account' => $user['account'],
|
||
'name' => $user['name'],
|
||
'group_id' => $user['group_id'],
|
||
'tid' => $tid, // 新增:租户ID
|
||
'tenant' => $tenant // 新增:租户名称
|
||
];
|
||
|
||
// 获取角色权限
|
||
if ($user['group_id']) {
|
||
$userGroup = AdminUserGroup::where('id', $user['group_id'])->find();
|
||
if ($userGroup && $userGroup->rights) {
|
||
$userInfo['rights'] = json_decode($userGroup->rights, true);
|
||
}
|
||
}
|
||
|
||
// 10. 生成Token(Token中已包含租户信息,后续可通过Token解析获取)
|
||
try {
|
||
$token = $this->generateToken($userInfo);
|
||
} catch (\Exception $e) {
|
||
$this->logFail('登录管理', '登录', 'Token生成失败: ' . $e->getMessage());
|
||
return json([
|
||
'code' => 500,
|
||
'msg' => '登录失败,请稍后重试'
|
||
]);
|
||
}
|
||
|
||
// 11. 写入用户数据缓存(核心:缓存包含租户信息,示例用Redis,可根据你的缓存工具调整)
|
||
try {
|
||
$cacheKey = 'admin_user_' . $user['id'] . '_' . $tid; // 缓存键加入租户ID,避免多租户冲突
|
||
$cacheExpire = 86400 * 7; // 缓存7天,可根据需求调整
|
||
// 写入缓存(这里假设你使用thinkphp的Cache类,若用其他工具可替换)
|
||
\think\facade\Cache::set($cacheKey, $userInfo, $cacheExpire);
|
||
} catch (\Exception $e) {
|
||
error_log('用户缓存写入失败: ' . $e->getMessage());
|
||
// 缓存写入失败不影响登录,但记录日志
|
||
}
|
||
|
||
// 12. 记录登录成功日志
|
||
try {
|
||
$this->logSuccess('登录管理', '登录', [
|
||
'id' => $user['id'],
|
||
'tid' => $tid,
|
||
'tenant' => $tenant
|
||
], $userInfo);
|
||
} catch (\Exception $e) {
|
||
error_log('登录日志记录失败: ' . $e->getMessage());
|
||
}
|
||
|
||
// 13. 返回登录结果(包含租户信息)
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '登录成功',
|
||
'data' => [
|
||
'token' => $token,
|
||
'user' => $userInfo // 前端可直接获取租户ID和名称
|
||
]
|
||
]);
|
||
} catch (\Exception $e) {
|
||
$errorMsg = $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine();
|
||
error_log('登录失败: ' . $errorMsg);
|
||
try {
|
||
$this->logFail('登录管理', '登录', $errorMsg);
|
||
} catch (\Exception $logError) {
|
||
error_log('记录登录失败日志也失败: ' . $logError->getMessage());
|
||
}
|
||
return json([
|
||
'code' => 500,
|
||
'msg' => '登录失败:' . $e->getMessage()
|
||
]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送手机号登录验证码
|
||
*/
|
||
public function sendLoginCode(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'phone|手机号' => 'require|mobile',
|
||
]);
|
||
|
||
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||
->where('status', 1)
|
||
->find();
|
||
if (!$tenant) {
|
||
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||
}
|
||
|
||
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||
->where('phone', (string)$data['phone'])
|
||
->where('status', 1)
|
||
->where('delete_time', null)
|
||
->find();
|
||
if (!$user) {
|
||
return json(['code' => 404, 'msg' => '手机号未绑定可用账号']);
|
||
}
|
||
|
||
return $this->sendSmsCodeInternal('login', (string)$data['tenant_name'], (string)$data['phone'], (string)$data['phone']);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 手机号验证码登录
|
||
*/
|
||
public function loginBySms(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'phone|手机号' => 'require|mobile',
|
||
'sms_code|短信验证码' => 'require|length:4,8',
|
||
]);
|
||
|
||
$codeKey = $this->smsCodeCacheKey('login', (string)$data['tenant_name'], (string)$data['phone'], (string)$data['phone']);
|
||
$cachedCode = (string)Cache::get($codeKey, '');
|
||
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||
}
|
||
|
||
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||
->where('status', 1)
|
||
->field(['id', 'tenant_name'])
|
||
->find();
|
||
if (!$tenant) {
|
||
return json(['code' => 401, 'msg' => '租户不存在或已禁用']);
|
||
}
|
||
|
||
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||
->where('phone', (string)$data['phone'])
|
||
->where('status', 1)
|
||
->where('delete_time', null)
|
||
->find();
|
||
if (!$user) {
|
||
return json(['code' => 401, 'msg' => '手机号未绑定可用账号']);
|
||
}
|
||
|
||
Cache::delete($codeKey);
|
||
return $this->buildLoginSuccessResponse($user, $tenant);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '登录失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 退出登录
|
||
* @return Json
|
||
*/
|
||
public function logout(): Json
|
||
{
|
||
$authHeader = $this->request->header('Authorization', '');
|
||
$userInfo = null;
|
||
|
||
if (preg_match('/Bearer\s+(.+)/i', $authHeader, $matches)) {
|
||
$tokenData = $this->verifyToken($matches[1]);
|
||
if ($tokenData && isset($tokenData['user'])) {
|
||
$userInfo = (array)$tokenData['user'];
|
||
}
|
||
}
|
||
|
||
if ($userInfo && isset($userInfo['id'])) {
|
||
$this->logSuccess('登录管理', '退出登录', ['result' => 'success'], $userInfo);
|
||
} else {
|
||
OperationLog::create([
|
||
'user_id' => 0,
|
||
'user_account' => '',
|
||
'user_name' => '未知用户',
|
||
'module' => '登录管理',
|
||
'action' => '退出登录',
|
||
'method' => 'POST',
|
||
'url' => $this->request->url(true),
|
||
'ip' => $this->request->ip(),
|
||
'user_agent' => $this->request->header('user-agent', ''),
|
||
'request_data' => null,
|
||
'response_data' => json_encode(['result' => 'success'], JSON_UNESCAPED_UNICODE),
|
||
'status' => 1,
|
||
'error_message' => '',
|
||
'execution_time' => 0.0,
|
||
]);
|
||
}
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '退出成功'
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取当前登录用户信息
|
||
* @return Json
|
||
*/
|
||
public function userInfo(): Json
|
||
{
|
||
$authHeader = $this->request->header('Authorization', '');
|
||
|
||
if (!preg_match('/Bearer\s+(.+)/i', $authHeader, $matches)) {
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '未登录'
|
||
]);
|
||
}
|
||
|
||
$tokenData = $this->verifyToken($matches[1]);
|
||
|
||
if (!$tokenData || !isset($tokenData['user'])) {
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => 'Token无效'
|
||
]);
|
||
}
|
||
|
||
$user = (array)$tokenData['user'];
|
||
$user_id = $user['id'];
|
||
|
||
$userData = AdminUser::where('id', $user_id)
|
||
->where('delete_time', null)
|
||
->field('id, account, name, phone, qq, sex, group_id, status, create_time, update_time')
|
||
->find();
|
||
|
||
if (!$userData) {
|
||
return json([
|
||
'code' => 404,
|
||
'msg' => '用户不存在'
|
||
]);
|
||
}
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => $userData->toArray()
|
||
]);
|
||
}
|
||
|
||
public function getAdminUserFromToken(): array
|
||
{
|
||
return JwtService::getUserFromHeader($this->request->header('Authorization', ''));
|
||
}
|
||
|
||
|
||
|
||
public function loginInfo()
|
||
{
|
||
|
||
$loginInfo = SystemSiteSettings::select();
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => $loginInfo
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 注册账号(按租户维度)
|
||
*/
|
||
public function sendRegisterCode(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'account|账号' => 'require|length:3,32',
|
||
'phone|手机号' => 'require|mobile',
|
||
]);
|
||
return $this->sendSmsCodeInternal('register', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
public function register(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'account|账号' => 'require|length:3,32',
|
||
'name|姓名' => 'require|length:2,32',
|
||
'password|密码' => 'require|length:6,32',
|
||
'confirm_password|确认密码' => 'require',
|
||
'phone|手机号' => 'require|mobile',
|
||
'sms_code|短信验证码' => 'require|length:4,8',
|
||
]);
|
||
|
||
if ((string)$data['password'] !== (string)$data['confirm_password']) {
|
||
return json(['code' => 400, 'msg' => '两次输入的密码不一致']);
|
||
}
|
||
|
||
$codeKey = $this->smsCodeCacheKey('register', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||
$cachedCode = (string)Cache::get($codeKey, '');
|
||
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||
}
|
||
|
||
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||
->where('status', 1)
|
||
->find();
|
||
if (!$tenant) {
|
||
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||
}
|
||
|
||
$exists = AdminUser::where('tid', (int)$tenant['id'])
|
||
->where('account', (string)$data['account'])
|
||
->where('delete_time', null)
|
||
->find();
|
||
if ($exists) {
|
||
return json(['code' => 400, 'msg' => '账号已存在']);
|
||
}
|
||
|
||
$now = date('Y-m-d H:i:s');
|
||
$user = new AdminUser();
|
||
$user->save([
|
||
'tid' => (int)$tenant['id'],
|
||
'account' => (string)$data['account'],
|
||
'name' => (string)$data['name'],
|
||
'phone' => (string)$data['phone'],
|
||
'email' => (string)($data['email'] ?? ''),
|
||
'password' => md5((string)$data['password']),
|
||
'status' => 1,
|
||
'group_id' => 0,
|
||
'login_count' => 0,
|
||
'create_time' => $now,
|
||
'update_time' => $now,
|
||
]);
|
||
|
||
Cache::delete($codeKey);
|
||
|
||
return json(['code' => 200, 'msg' => '注册成功']);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '注册失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 忘记密码:通过租户 + 账号 + 手机号重置密码
|
||
*/
|
||
public function sendResetCode(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'account|账号' => 'require|length:3,32',
|
||
'phone|手机号' => 'require|mobile',
|
||
]);
|
||
|
||
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||
->where('status', 1)
|
||
->find();
|
||
if (!$tenant) {
|
||
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||
}
|
||
|
||
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||
->where('account', (string)$data['account'])
|
||
->where('phone', (string)$data['phone'])
|
||
->where('delete_time', null)
|
||
->find();
|
||
if (!$user) {
|
||
return json(['code' => 404, 'msg' => '账号不存在或手机号不匹配']);
|
||
}
|
||
|
||
return $this->sendSmsCodeInternal('reset', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '发送失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
public function resetPassword(): Json
|
||
{
|
||
try {
|
||
$data = $this->request->post();
|
||
$this->validate($data, [
|
||
'tenant_name|租户名称' => 'require|length:1,128',
|
||
'account|账号' => 'require|length:3,32',
|
||
'phone|手机号' => 'require|mobile',
|
||
'new_password|新密码' => 'require|length:6,32',
|
||
'confirm_password|确认密码' => 'require',
|
||
'sms_code|短信验证码' => 'require|length:4,8',
|
||
]);
|
||
|
||
if ((string)$data['new_password'] !== (string)$data['confirm_password']) {
|
||
return json(['code' => 400, 'msg' => '两次输入的密码不一致']);
|
||
}
|
||
|
||
$codeKey = $this->smsCodeCacheKey('reset', (string)$data['tenant_name'], (string)$data['account'], (string)$data['phone']);
|
||
$cachedCode = (string)Cache::get($codeKey, '');
|
||
if ($cachedCode === '' || $cachedCode !== (string)$data['sms_code']) {
|
||
return json(['code' => 400, 'msg' => '短信验证码错误或已过期']);
|
||
}
|
||
|
||
$tenant = Tenant::where('tenant_name', (string)$data['tenant_name'])
|
||
->where('status', 1)
|
||
->find();
|
||
if (!$tenant) {
|
||
return json(['code' => 400, 'msg' => '租户不存在或已禁用']);
|
||
}
|
||
|
||
$user = AdminUser::where('tid', (int)$tenant['id'])
|
||
->where('account', (string)$data['account'])
|
||
->where('phone', (string)$data['phone'])
|
||
->where('delete_time', null)
|
||
->find();
|
||
if (!$user) {
|
||
return json(['code' => 404, 'msg' => '账号不存在或手机号不匹配']);
|
||
}
|
||
|
||
AdminUser::where('id', (int)$user['id'])->update([
|
||
'password' => md5((string)$data['new_password']),
|
||
'update_time' => date('Y-m-d H:i:s'),
|
||
]);
|
||
|
||
Cache::delete($codeKey);
|
||
|
||
return json(['code' => 200, 'msg' => '密码重置成功']);
|
||
} catch (ValidateException $e) {
|
||
return json(['code' => 400, 'msg' => $e->getError()]);
|
||
} catch (\Throwable $e) {
|
||
return json(['code' => 500, 'msg' => '重置失败:' . $e->getMessage()]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取极验3.0的id和key
|
||
* @return Json
|
||
*/
|
||
public function getGeetest3Infos()
|
||
{
|
||
// 定义你需要的 label 列表
|
||
$targetLabels = [
|
||
'geetest3ID',
|
||
'geetest3KEY'
|
||
];
|
||
|
||
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||
->field('label, value')
|
||
->select();
|
||
|
||
$this->logSuccess('站点设置管理', '查看极验3.0的id和key', [], $this->getAdminUserInfo());
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => $legalInfos->toArray()
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 获取极验4.0的id和key
|
||
* @return Json
|
||
*/
|
||
public function getGeetest4Infos()
|
||
{
|
||
// 定义你需要的 label 列表
|
||
$targetLabels = [
|
||
'geetest4ID',
|
||
'geetest4KEY'
|
||
];
|
||
|
||
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||
->field('label, value')
|
||
->select()
|
||
->toArray();
|
||
|
||
// 转换为前端需要的格式
|
||
$data = [];
|
||
foreach ($legalInfos as $item) {
|
||
if ($item['label'] === 'geetest4ID') {
|
||
$data['captcha_id'] = $item['value'];
|
||
}
|
||
if ($item['label'] === 'geetest4KEY') {
|
||
$data['captcha_key'] = $item['value'];
|
||
}
|
||
}
|
||
|
||
$this->logSuccess('站点设置管理', '查看极验4.0的id和key', [], $this->getAdminUserInfo());
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => $data
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* 判断是否开启验证
|
||
* @return Json
|
||
*/
|
||
public function getOpenVerify()
|
||
{
|
||
// 定义你需要的 label 列表
|
||
$targetLabels = [
|
||
'openVerify',
|
||
'verifyModel'
|
||
];
|
||
|
||
$legalInfos = SystemSiteSettings::where('delete_time', null)
|
||
->whereIn('label', $targetLabels) // 仅筛选指定的 label
|
||
->field('label, value')
|
||
->select();
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'msg' => '获取成功',
|
||
'data' => $legalInfos->toArray()
|
||
]);
|
||
}
|
||
}
|