Files
YwxAppThink/app/member/controller/Register.php
T
yangwx 18101cf11a feat: 上线前安全加固与发布工程化;appmall 由插件迁移为独立应用
安全(P0)
- 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、
  ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签
  (ywxapp.framework_package_verify,默认开启)
- JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret()
  校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET
- /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验
- 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流
- TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive
- 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php)
- 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis
- paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG

工程化 / 交付
- 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本
- 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过
- 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障
- .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess

结构
- appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
2026-10-22 00:53:39 +08:00

148 lines
5.3 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 app\member\controller;
use app\member\validate\Register as RegisterValidate;
use think\exception\ValidateException;
use think\facade\Env;
use think\facade\Event;
use think\Request;
use ywxapp\controller\MemberBase;
use ywxapp\library\Sms;
use ywxapp\model\CommonSms as SmsModel;
use ywxapp\model\MemberUser as UserModel;
use ywxapp\model\MemberProfile;
use ywxapp\model\MemberGroupAccess;
use ywxapp\service\ScoreService;
/**
* Register 类
*
* @author ywxapp <admin@ywxapp.cn>
*/
class Register extends MemberBase
{
/**
* 无需登录即可访问注册相关接口
* @var array
*/
protected $noNeedLogin = ['*'];
/**
* @var array
*/
protected $noNeedVerify = ['*'];
protected function initialize()
{}
/**
* 注册页
*/
public function index()
{
$this->view->layout(false);
return $this->view->fetch();
}
/**
* 发送注册短信验证码
* 事件驱动:SmsSend 由短信插件实际下发;开发环境默认监听空发并回传验证码。
*/
public function sendsms()
{
if (!($this->request->isAjax() && $this->request->isPost())) {
$this->result->error('访问错误');
}
$cellphone = (string)$this->request->param('cellphone', '');
if (!preg_match('/^1[3-9]\d{9}$/', $cellphone)) {
$this->result->error('手机号格式不正确', 1);
}
if (UserModel::where('mobile', $cellphone)->whereOr('account', $cellphone)->find()) {
$this->result->error('该手机号已注册', 1);
}
if (!Sms::send($cellphone, null, 'register')) {
$this->result->error('验证码发送失败', 1);
}
// 开发模式把验证码回传前端便于测试
if (Env::get('app_debug')) {
$code = SmsModel::where(['mobile' => $cellphone, 'event' => 'register'])
->order('id', 'DESC')->value('code');
$this->result->success(['debug_code' => $code]);
}
$this->result->success();
}
/**
* 注册提交
* 流程:校验表单 → 校验短信验证码 → 创建用户(模型自动加盐哈希密码)
* → 写入资料/用户组 → 触发 UserRegister / MemberLog 事件(插件钩子点)
*/
public function save(Request $request)
{
if (!($this->request->isAjax() && $this->request->isPost())) {
$this->result->error('访问错误');
}
$data = $this->request->param();
try {
validate(RegisterValidate::class)->check($data);
} catch (ValidateException $e) {
$this->result->error($e->getMessage(), 1);
}
// 校验短信验证码(Sms::check 比对数据库,无需监听)
if (!Sms::check($data['cellphone'], $data['vercode'], 'register')) {
$this->result->error('验证码错误或已过期', 1);
}
if (UserModel::where('mobile', $data['cellphone'])->whereOr('account', $data['cellphone'])->find()) {
$this->result->error('该手机号已注册', 1);
}
$user = UserModel::create([
'account' => $data['cellphone'],
'mobile' => $data['cellphone'],
'nickname' => $data['nickname'],
'email' => $data['cellphone'] . '@mobile.local', // 手机号注册无邮箱,写入唯一占位避免唯一键冲突
'password' => $data['password'], // 触发模型 setPasswordAttr 自动加盐哈希
'status' => 1,
'gid' => 2, // 普通会员组(wxapp_user_group.id=2)
'create_ip' => $this->request->ip(),
'update_ip' => $this->request->ip(),
]);
// 建立用户资料行与默认用户组
MemberProfile::create(['uid' => $user->uid]);
MemberGroupAccess::create(['uid' => $user->uid, 'gid' => 2]);
// ===== 插件事件触发点 =====
// UserRegister:业务扩展钩子,插件可在此发欢迎信、初始化钱包、分配角色等
Event::trigger('UserRegister', ['member' => $user, 'data' => $data]);
// 积分规则引擎:注册送积分(规则在后台「积分规则」按 user.register 配置,未配置则静默跳过)
ScoreService::trigger('user.register', (int) $user->uid, [
'account' => $data['cellphone'] ?? '',
'nickname' => $data['nickname'] ?? '',
], ['source' => 'member', 'source_id' => 'u' . $user->uid]);
// MemberLog:审计钩子(可监听写入 wxapp_user_log)
Event::trigger('MemberLog', [
'uid' => $user->uid,
'action' => 'register',
'ip' => $this->request->ip(),
'remark' => '用户注册',
]);
Sms::flush($data['cellphone'], 'register');
$this->result->success();
}
}