Files
YwxAppThink/addon/haonav/controller/Account.php
T

136 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace addon\haonav\controller;
use ywxapp\controller\FrontendBase;
use ywxapp\model\MemberUser as UserModel;
/**
* 前台会员登录 / 注册 / 退出 / 资料
*
* 复用框架前台 AuthAuthorization 头或 access_token Cookie)。
* 登录/注册成功后 JwtService 把 token 写入 Result 单例,
* 由 Result::applyTokenCookies() 随响应写回非 httpOnly Cookiepath=/),
* 前端(整页/iframe)后续请求自动带登录态,无需前端额外存储。
*
* 注:框架 Auth::register() 内部依赖不存在的 UserModel::checkExists()
* 故注册在此控制器用 Member 模型直接建号,再用 Auth::login() 建立登录态与 token。
*
* @author ywxapp <admin@ywxapp.cn>
*/
class Account extends FrontendBase
{
protected $noNeedLogin = ['login', 'register'];
protected $noNeedVerify = ['*'];
/**
* 规整要返回给前端的用户资料
*/
protected function userInfo(): array
{
$info = $this->auth->info ?? [];
if (is_object($info)) {
$info = $info->toArray();
}
return [
'uid' => (int)($info['uid'] ?? 0),
'account' => (string)($info['account'] ?? ''),
'nickname' => (string)($info['nickname'] ?? ''),
'avatar' => (string)($info['avatar'] ?? ''),
];
}
/**
* 登录
* POST /haonav/account/login {account, password}
*/
public function login()
{
$account = trim((string)$this->request->post('account', ''));
$password = (string)$this->request->post('password', '');
if ($account === '' || $password === '') {
return $this->result->error('请输入账号和密码');
}
try {
$this->auth->login($account, $password);
} catch (\Throwable $e) {
// Auth::login 内部已通过 Result 输出错误则不会到这里;此处兜底
return $this->result->error('登录失败:' . $e->getMessage());
}
return $this->result->success($this->userInfo(), '登录成功');
}
/**
* 注册
* POST /haonav/account/register {account, password, nickname?}
*/
public function register()
{
$account = trim((string)$this->request->post('account', ''));
$password = (string)$this->request->post('password', '');
$nickname = trim((string)$this->request->post('nickname', ''));
if ($account === '' || $password === '') {
return $this->result->error('请输入账号和密码');
}
if (mb_strlen($password) < 6) {
return $this->result->error('密码至少 6 位');
}
if (!preg_match('/^[\x{4e00}-\x{9fa5}a-zA-Z0-9_@.\-]+$/u', $account)) {
return $this->result->error('账号仅支持中英文、数字、_@.- 等字符');
}
// 账号查重(框架 UserModel::checkExists 不存在,这里直接查询)
if (UserModel::where('account', $account)->findOrEmpty()->isExists()) {
return $this->result->error('该账号已被注册');
}
$user = new UserModel();
$user->account = $account;
$user->nickname = $nickname !== '' ? mb_substr($nickname, 0, 30) : ('用户' . mb_substr($account, 0, 4));
// email 为 NOT NULL + 唯一:用本地占位邮箱保证唯一且不报错(非真实邮箱)
$user->email = $account . '@haonav.local';
$user->password = $password; // 触发 Member 模型 setPasswordAttr 自动加盐加密
$user->status = 1;
$user->gid = (int)config('fastadmin.user_default_group') ?: 0;
$user->create_ip = $this->request->ip();
$user->update_ip = $this->request->ip();
$user->save();
// 建号后建立登录态并写回 token Cookie
try {
$this->auth->login($account, $password);
} catch (\Throwable $e) {
return $this->result->error('注册成功但自动登录失败,请手动登录');
}
return $this->result->success($this->userInfo(), '注册成功');
}
/**
* 退出登录
* POST /haonav/account/logout
*/
public function logout()
{
$this->auth->logout();
return $this->result->success([], '已退出登录');
}
/**
* 当前登录资料(用于前端刷新登录态)
* GET /haonav/account/profile
*/
public function profile()
{
if (! $this->auth || ! $this->auth->isLogin) {
return $this->result->error('未登录', 401);
}
return $this->result->success($this->userInfo());
}
}