Files
chat/backend/app/controller/api/Auth.php
T
2026-07-22 10:18:59 +08:00

161 lines
5.2 KiB
PHP

<?php
namespace app\controller\api;
use app\model\User;
use app\model\MembershipLevel;
use app\model\Role;
use app\service\JwtService;
use app\service\SettingsService;
use app\service\UserContextService;
class Auth extends BaseApi
{
public function guest()
{
$guestKey = strtolower(trim((string) $this->request->post('guest_key', '')));
if (!preg_match('/^[a-f0-9]{64}$/', $guestKey)) {
return $this->error('游客标识无效,请刷新页面重试', 422);
}
// Only persist a one-way fingerprint; the random browser key remains the credential.
$fingerprint = hash('sha256', $guestKey);
$username = 'guest_' . substr($fingerprint, 0, 32);
$user = User::where('username', $username)->find();
if (!$user) {
$roleId = Role::where('slug', 'user')->value('id');
$membershipId = MembershipLevel::where('slug', 'free')->value('id') ?: 1;
try {
$user = User::create([
'username' => $username,
'email' => $username . '@guest.local',
'password_hash' => password_hash(bin2hex(random_bytes(32)), PASSWORD_BCRYPT),
'nickname' => '访客',
'role' => 'user',
'role_id' => $roleId ?: null,
'membership_level_id' => $membershipId,
'status' => 'active',
]);
} catch (\Throwable $exception) {
// Two tabs may initialize the same browser guest at the same time.
$user = User::where('username', $username)->find();
if (!$user) {
throw $exception;
}
}
}
if ($user->status !== 'active') {
return $this->error('游客访问暂不可用', 403);
}
$token = JwtService::generateToken(['user_id' => $user->id]);
return $this->success([
'token' => $token,
'user' => $this->formatUser($user->id),
], '已进入游客模式');
}
public function register()
{
$allow = SettingsService::get('allow_register', true);
if ($allow !== true && $allow !== 'true') {
return $this->error('当前不允许注册');
}
$input = $this->request->post();
$username = trim($input['username'] ?? '');
$email = trim($input['email'] ?? '');
$password = $input['password'] ?? '';
if (strlen($username) < 3 || strlen($username) > 50) {
return $this->error('用户名长度需 3-50 个字符');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return $this->error('邮箱格式不正确');
}
if (strlen($password) < 6) {
return $this->error('密码至少 6 位');
}
if (User::where('username', $username)->whereOr('email', $email)->find()) {
return $this->error('用户名或邮箱已存在');
}
$defaultRoleId = \app\model\Role::where('slug', 'user')->value('id');
$user = User::create([
'username' => $username,
'email' => $email,
'password_hash' => password_hash($password, PASSWORD_BCRYPT),
'nickname' => $username,
'membership_level_id' => 1,
'role_id' => $defaultRoleId ?: null,
]);
$token = JwtService::generateToken(['user_id' => $user->id]);
return $this->success([
'token' => $token,
'user' => $this->formatUser($user->id),
], '注册成功');
}
public function login()
{
$input = $this->request->post();
$account = trim($input['account'] ?? '');
$password = $input['password'] ?? '';
if (!$account || !$password) {
return $this->error('请输入账号和密码');
}
$user = User::where(function ($query) use ($account) {
$query->where('username', $account)->whereOr('email', $account);
})->where('status', 'active')->find();
if (!$user || !password_verify($password, $user->password_hash)) {
return $this->error('账号或密码错误', 401);
}
$user->save(['last_login_at' => date('Y-m-d H:i:s')]);
$token = JwtService::generateToken(['user_id' => $user->id]);
return $this->success([
'token' => $token,
'user' => $this->formatUser($user->id),
], '登录成功');
}
public function me()
{
return $this->success($this->authUser());
}
public function updateProfile()
{
$user = $this->authUser();
$nickname = trim($this->request->put('nickname', ''));
if ($nickname) {
User::where('id', $user['id'])->update(['nickname' => $nickname]);
}
return $this->success($this->formatUser($user['id']));
}
public function logout()
{
return $this->success(null, '已退出');
}
private function formatUser(int $userId): array
{
return UserContextService::formatPublicUser($userId);
}
}