/** * 检查密码是否正确 * * @param string $field * @param string $password * @param bool $secretly * @return array * @throws UserException */ public function checkPasswordCredential($field, $password, $secretly = false) { if (Validator::email()->validate($field)) { $user = UserUtil::getUserObjectByEmail($field); } else { $user = UserUtil::getUserObjectByUsername($field); } if (!UserUtil::isUserObjectValid($user)) { if (!$secretly) { Application::emit('user.login.failed.user_invalid', [VJ::LOGIN_TYPE_FAILED_USER_INVALID, $field]); Application::info('credential.login.not_found', ['login' => $field]); } throw new UserException('UserCredential.checkPasswordCredential.user_not_valid'); } $verified = $this->password_encoder->verify($password, $user['salt'], $user['hash']); if (!$verified) { if (!$secretly) { Application::emit('user.login.failed.wrong_password', [VJ::LOGIN_TYPE_FAILED_WRONG_PASSWORD, $user]); Application::info('credential.login.wrong_password', ['uid' => $user['uid']]); } throw new UserException('UserCredential.checkPasswordCredential.wrong_password'); } if (!$secretly) { Application::emit('user.login.succeeded', [VJ::LOGIN_TYPE_INTERACTIVE, $user, $field, $password]); Application::info('credential.login.ok', ['uid' => $user['uid']]); } return $user; }
/** * 创建用户 * * @param string $username * @param string $password * @param string $email * @return int UID * @throws InvalidArgumentException * @throws UserException */ public function createUser($username, $password, $email) { if (!is_string($username)) { throw new InvalidArgumentException('username', 'type_invalid'); } if (!is_string($password)) { throw new InvalidArgumentException('password', 'type_invalid'); } if (!is_string($email)) { throw new InvalidArgumentException('email', 'type_invalid'); } // 检查用户名 if (!mb_check_encoding($username, 'UTF-8')) { throw new InvalidArgumentException('username', 'encoding_invalid'); } $username = trim($username); if (!Validator::regex('/^\\S*$/')->length(3, 16)->validate($username)) { throw new InvalidArgumentException('username', 'format_invalid'); } // 检查关键字 $keyword = KeywordFilter::isContainGeneric($username); if ($keyword === false) { $keyword = KeywordFilter::isContainName($username); } if ($keyword !== false) { throw new UserException('UserManager.name_forbid', ['keyword' => $keyword]); } // 检查密码 if (!Validator::length(0, 50)->validate($password)) { throw new InvalidArgumentException('password', 'format_invalid'); } // 检查 email if (!Validator::email()->validate($email)) { throw new InvalidArgumentException('password', 'format_invalid'); } // 处理用户名 $username = VJ::removeEmoji($username); // 检查用户名和 Email 是否唯一 if (UserUtil::getUserObjectByUsername($username) !== null) { throw new UserException('UserManager.createUser.user_exists'); } if (UserUtil::getUserObjectByEmail($email) !== null) { throw new UserException('UserManager.createUser.email_exists'); } // 生成 hash & salt $hashSaltPair = $this->user_credential->password_encoder->generateHash($password); // 插入记录 try { $_id = new \MongoId(); $doc = ['_id' => $_id, 'uid' => $_id, 'user' => $username, 'luser' => UserUtil::canonicalizeUsername($username), 'mail' => $email, 'lmail' => UserUtil::canonicalizeEmail($email), 'salt' => $hashSaltPair['salt'], 'hash' => $hashSaltPair['hash'], 'g' => $email, 'gender' => VJ::USER_GENDER_UNKNOWN, 'regat' => new \MongoDate(), 'regip' => $this->request->getClientIp()]; Application::coll('User')->insert($doc); } catch (\MongoCursorException $e) { // 插入失败 throw new UserException('UserManager.createUser.user_or_email_exists'); } // 插入成功:更新 uid // 获取递增 uid $counterRec = Application::coll('System')->findAndModify(['_id' => 'UserCounter'], ['$inc' => ['count' => 1]], [], ['new' => true, 'upsert' => true]); $uid = (int) $counterRec['count']; try { // 修改 uid Application::coll('User')->update(['_id' => $_id], ['$set' => ['uid' => $uid]]); } catch (\MongoCursorException $e) { // 修改 uid 失败(uid 重复),则删除用户记录 Application::critical('createUser.uidDuplicate', ['uid' => $uid]); Application::coll('User')->remove(['_id' => $_id], ['justOne' => true]); throw new UserException('UserManager.createUser.internal'); } Application::emit('user.created', [$uid]); return $uid; }