提示
本教程相关代码托管在Gitee:gitee.com/toshcn/micr…
创建User账号登录表单,通过表单接收前端输入,验证输入的数据,返回用户接口令牌,后续使用用户令牌调用需要登录的其它接口。
修改User模型类,增加通过手机号码查找用户模型方法
打开common/models/User.php文件,修改内容如下:
<?php
/**
* @link https://gitee.com/toshcn/micro-hau
* @copyright Copyright (c) 2022/4/16 micro-hau
* @author toshcn <toshcn@foxmail.com>
*/
namespace common\models;
use Yii;
use yii\db\ActiveRecord; // 活动记录模型
use yii\filters\RateLimitInterface; // 速率限制接口
use yii\web\IdentityInterface; // 用户身份接口
// ...
class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
{
// ...
/**
* 登录成功后事件处理器
* @param object $event 事件对象
* @return bool
*/
public static function afterLoginHandler($event) // &$event 修改为$event
{
return true; // todo
}
// 增加如下方法
/**
* 通过手机号码查找用户
* @param number $mobile 手机号码
* @param int $countryCode 国家代码
* @return User|null
*/
public static function findByMobile($mobile, $countryCode = 86)
{
return static::findOne(['mobile' => $mobile, 'country_code' => (int) $countryCode]);
}
/**
* 登录成功返回登录令牌等用户信息
* @throws \yii\base\Exception
*/
public function loginInfo()
{
// 更新令牌
$this->generateAccessToken();
return [
'uid' => (int) $this->id,
'nickname' => $this->nickname,
'avatar' => $this->avatar,
'token' => $this->access_token,
'tokenExpire' => $this->access_token_expire
];
}
}
创建User账号登录表单类
在项目api/modules/v1/forms目录下创建UserLoginForm.php文件,文件内容如下:
<?php
/**
* @link https://gitee.com/toshcn/micro-hau
* @copyright Copyright (c) 2022/4/29 micro-hau
* @author toshcn <toshcn@foxmail.com>
*/
namespace api\modules\v1\forms;
use Yii;
use common\models\User;
use common\models\BaseModel;
/**
* User模型登录表单
* Class UserForm
* @package api\modules\v1\forms
*/
class UserLoginForm extends BaseModel
{
public $mobile; // 用户账号手机号
public $countryCode = 86; // 用户账号手机号国家代码: 86(中国)
public $password; // 用户账号密码
/** @var null|User */
private $_user = null; // 用户对象
/**
* 表单字段规则
* @return array
*/
public function rules()
{
return [
[['mobile', 'password'], 'trim'],
[['countryCode'], 'number', 'skipOnError' => true],
[['mobile', 'countryCode', 'password'], 'required'],
['mobile', 'validateMobile', 'skipOnError' => true], // 行内验证器 检测手机号码
['password', 'validatePassword', 'skipOnError' => true], // 行内验证器 检测密码强度
];
}
/**
* 检测手机号
* @param string $attribute 当前检测的字段名
* @param array $params 以名-值对形式提供的额外参数
* @param \yii\validators\InlineValidator $validator 当前行内验证器 InlineValidator实例。此参数自版本 Yii 2.0.11 起可用。
*/
public function validateMobile($attribute, $params, $validator)
{
if (!$this->hasErrors()) {
if (!Yii::$app->utils->regExp($this->$attribute, 'cn_mobile')) {
// 检测手机号码格式
$validator->addError($this, $attribute, Yii::t('common', 'The mobile "{value}" is invalid.'));
} else {
// 检测手机号是否已注册
$this->_user = User::findByMobile($this->mobile, $this->countryCode);
if (empty($this->_user)) {
$validator->addError($this, $attribute, Yii::t('common', 'The account is not registered.'));
}
}
}
}
/**
* 检测密码
* @param string $attribute 当前检测的字段名
* @param array $params 以名-值对形式提供的额外参数
* @param \yii\validators\InlineValidator $validator 当前行内验证器 InlineValidator实例。此参数自版本 2.0.11 起可用。
*/
public function validatePassword($attribute, $params, $validator)
{
if (!$this->hasErrors()) {
if (empty($this->_user) || !$this->_user->validatePassword($this->$attribute)) {
$this->addError($attribute, Yii::t('common', 'Password verification failed.'));
}
}
}
/**
* 返回用户对象
* @return null|@common\models\User
*/
public function getUser()
{
return $this->_user;
}
/**
* 登录账号
* @return bool
*/
public function login()
{
// rules()规则都验证通过
if ($this->validate()) {
if (Yii::$app->getUser()->login($this->_user)) {
return true;
}
}
return false;
}
}
修改AccountControll账号控制器类,增加账号登录方法
打开api/modules/v1/controllers目录下的AccountControll.php文件,文件修改内容如下:
<?php /** @noinspection PhpUndefinedFieldInspection */
/**
* @link https://gitee.com/toshcn/micro-hau
* @copyright Copyright (c) 2022/4/22 micro-hau
* @author toshcn <toshcn@foxmail.com>
*/
namespace api\modules\v1\controllers;
use Yii;
use api\controllers\ApiController;
use api\modules\v1\forms\UserRegisterForm;
use api\modules\v1\forms\UserLoginForm;
/**
* 账号登录,注册相关控制器
* Class AccountController
* @package api\modules\v1\controllers
*/
class AccountController extends ApiController
{
// ...
// 增加的方法
/**
* @return mixed
*/
public function actionLogin()
{
$this->validateIsPost();
$form = new UserLoginForm();
// 从post中取出数据,赋值给登录表单对应字段
if ($form->load(Yii::$app->getRequest()->post(), '') && $form->login()) {
return Yii::$app->api->success($form->getUser()->loginInfo());
}
if ($form->hasErrors()) {
return Yii::$app->api->error(parent::ERROR_CODE_FORM_FIELD_ERROR, $form->getFirstOneError());
}
return Yii::$app->api->error(parent::ERROR_CODE_FORM_ERROR, Yii::t('common', 'Account login failed.'));
}
}
修改api配置requry组件
关闭表单csrf检测
// ...
return [
// ...
'components' => [
// ...
// 配置api接收请求组件
'request' => [
'csrfParam' => '_csrf-api',
// 关闭csrf检测 接口不需要 增加的配置
'enableCsrfValidation' => false,
'enableCsrfCookie' => false,
// 配置api接收JSON数据
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
]
]
测试接口
用Postman模拟请求www.mysite.local/v1/account/… mysite.local 替换为实际的主机名,设置请求标头content-type为application/json; charset=UTF-8,
提交表单如:
{
"mobile": "13188888888",
"password": "Test12345678"
}
将会看到如下内容:
{
"status": 1,
"code": 1,
"message": "success",
"data": {
"uid": 1,
"nickname": "test",
"avatar": "",
"token": "4383fb0cc3aa122d8aa3550e993d936c",
"tokenExpire": 1651840095
}
}