提示
本教程相关代码托管在Gitee:gitee.com/toshcn/micr…
配置数据库参数
打开common/config/main-local.php文件,修改数据库连接Mysql,如你的数据库名为micro_hau_db,账号为root,密码为123456:
<?php
// 本地相关配置项
return [
'components' => [
// 配置数据库组件
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=micro_hau_db', // 数据库连接
'username' => 'root', // 数据库账号
'password' => '123456', // 数据库账号密码
'charset' => 'utf8', // 数据库连接字符集
'tablePrefix' => 'hau_', // 表前缀
],
]
];
创建user表数据库迁移
在项目根目录下,打开命令行终端,运行php yii migrate/create user命令,输入yes看到如下内容:
$ php yii migrate/create user
Yii Migration Tool (based on Yii v2.0.45)
Create new migration 'D:\works\yii\micro-hau\console/migrations\m220416_133208_u
ser.php'? (yes|no) [no]:yes
New migration created successfully.
查看console/migrateions目录,是否已生成对应的文件,类名称按照 m<YYMMDD_HHMMSS>_ 的格式自动生成。 打开生成的文件,修改为以下内容:
<?php
use yii\db\Migration;
/**
* Class m220416_133208_user
*/
class m220416_133208_user extends Migration
{
const TB_USER = '{{%user}}'; // 用户表
/**
* {@inheritdoc}
*/
public function safeUp()
{
$userOptions = null;
if ($this->db->driverName === 'mysql') {
// http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci
$userOptions = 'CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE=InnoDB AUTO_INCREMENT=1';
}
$this->createTable(self::TB_USER, [
'id' => $this->primaryKey()->unsigned()->unique(),
'country_code' => $this->smallInteger()->unsigned()->notNull()->defaultValue(86)->comment('国家代码'),
'mobile' => $this->bigInteger(11)->unsigned()->notNull()->defaultValue(0)->comment('手机号'),
'nickname' => $this->string(20)->notNull()->defaultValue('')->comment('昵称'),
'avatar' => $this->string(255)->notNull()->defaultValue('')->comment('头像链接地址'),
'password_hash' => $this->string(72)->notNull()->comment('账号密码'),
'password_salt' => $this->char(20)->notNull()->comment('密码加密盐'),
'access_token' => $this->string(32)->unique()->notNull()->comment('API登录令牌'),
'access_token_expire' => $this->bigInteger()->unsigned()->notNull()->defaultValue(0)->comment('API登录令牌有效时长'),
'status' => $this->boolean()->notNull()->defaultValue(10)->comment('账号状态:-1已注销,0黑名单,10激活'),
'created_at' => $this->dateTime()->notNull(),
'updated_at' => $this->dateTime()->notNull(),
], $userOptions);
// 创建手机号为索引
$this->createIndex('idx-mobile', self::TB_USER, ['mobile', 'country_code', 'status']);
// 创建昵称为索引
$this->createIndex('idx-nickname', self::TB_USER, ['nickname', 'status']);
}
/**
* {@inheritdoc}
*/
public function safeDown()
{
if (YII_ENV_DEV) {
// 如果是测试环境 删除用户表
$this->dropTable(self::TB_USER);
return true;
}
echo "m220416_133208_user cannot be reverted.\n";
return false;
}
}
运行user表数据库迁移
在项目根目录下,打开命令行终端,运行php yii migrate命令,输入yes看到如下内容:
$ php yii migrate
Yii Migration Tool (based on Yii v2.0.45)
Creating migration history table "hau_migration"...Done.
Total 1 new migration to be applied:
m220416_133208_user
Apply the above migration? (yes|no) [no]:yes
*** applying m220416_133208_user
> create table {{%user}} ... done (time: 0.990s)
> create index idx-mobile on {{%user}} (mobile,country_code,status) ... done
(time: 0.107s)
> create index idx-nickname on {{%user}} (nickname,status) ... done (time: 0
.185s)
*** applied m220416_133208_user (time: 1.558s)
1 migration was applied.
Migrated up successfully.
表示成功生成用户表。
创建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\modules;
use Yii;
use yii\db\ActiveRecord; // 活动记录模型
use yii\filters\RateLimitInterface; // 速率限制接口
use yii\web\IdentityInterface; // 用户身份接口
/**
* user表模型类 继承ActiveRecord活动记录类
* 并需实现两个接口:RateLimitInterface速率限制接口 IdentityInterface 用户身份接口
* This is the model class for table "{{%user}}".
*
* @property int $id 自增id
* @property int $country_code 国家代码
* @property int $mobile 手机号
* @property string $nickname 账号昵称
* @property string $avatar 头像链接地址
* @property string $password_hash 账号密码
* @property string $password_salt 密码盐
* @property string $access_token API登录令牌
* @property int $access_token_expire API登录令牌有效时长
* @property int $status 账号状态:账号状态:-1已注销,0黑名单,10激活
* @property string $created_at 创建时间
* @property string $updated_at 更新时间
*/
class User extends ActiveRecord implements IdentityInterface, RateLimitInterface
{
const STATUS_CANCEL = -1; // 账号状态码 已注销
const STATUS_BLACK = 0; // 账号状态码 黑名单
const STATUS_ACTIVE = 10; // 账号状态码 正常
/**
* 返回用户表表名
* @return string
*/
public static function tableName()
{
return '{{%user}}'; // 前%为表前缀,如果有后缀需要在表名user后加%: 即{{%user%}}
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['mobile', 'country_code', 'access_token_expire', 'status'], 'integer'], // 限定字段为数字
[['password_hash', 'password_salt', 'access_token'], 'required'], // 限定字段为必需
[['nickname'], 'string', 'max' => 20], // 限制昵称最长20个字符
[['avatar'], 'string', 'max' => 255], // 限制头像地址最长255个字符
[['password_hash'], 'string', 'max' => 72],
[['password_salt'], 'string', 'max' => 20],
[['access_token'], 'string', 'max' => 32],
[['access_token'], 'unique'],
// 限制手国家代码+机号码唯一
[['mobile', 'country_code'], 'unique', 'targetAttribute' => ['mobile', 'country_code']],
['status', 'default', 'value' => static::STATUS_ACTIVE], // 账号默认状态
['status', 'in', 'range' => [static::STATUS_ACTIVE, static::STATUS_BLACK, static::STATUS_CANCEL]],
[['created_at', 'updated_at'], 'safe'],
];
}
/**
* 实现查找用户接口
* 通过用户ID方式 查找用户表对应记录
* @param int|string $id 用户表自增ID字段
* @return User|null|IdentityInterface 返回用户模型对象
*/
public static function findIdentity($id)
{
return static::findOne(['id' => (int) $id]);
}
/**
* 实现查找用户接口
* 通过access_token方式
* @param string $token 令牌
* @param null $type 令牌类型
* @return array|null|\yii\db\ActiveRecord
*/
public static function findIdentityByAccessToken($token, $type = null)
{
// 通过令牌找到用户,令牌需未过期
return static::find()
->where(['and', ['access_token' => $token], ['>', 'access_token_expire', time()]])
->one();
}
/**
* 实现获取用户ID接口
* @return int|mixed|string
*/
public function getId()
{
return $this->getPrimaryKey();
}
/**
* 实现getAuthKey接口
* @return null|string
*/
public function getAuthKey()
{
return '';
}
/**
* 实现验证authKey接口
* @param string $authKey
* @return bool|null
*/
public function validateAuthKey($authKey)
{
return false;
}
/**
* 实现请求速率限制接口
* 返回允许的请求速率最大数目及限制时间
* @param \yii\web\Request $request 当前请求
* @param \yii\base\Action $action 执行的动作
* @return array
*/
public function getRateLimit($request, $action)
{
// 表示在 3 秒内最多 500 次的 API 调用
return [500, 3];
}
/**
* 实现请求速率限制接口
* 返回当前允许的请求次数和最后一次速率限制检查时 相应的 UNIX 时间戳数
* @param \yii\web\Request $request 当前请求
* @param \yii\base\Action $action 执行的动作
* @return array. 数组第一个元素为当前允许请求的次数, 第二个元素为相应的时间戳.
*/
public function loadAllowance($request, $action)
{
// 从缓存中获取用户允许的请求次数 和 最后一次速率限制检查时间戳
$limit = (int) Yii::$app->getCache()->get('rateLimiter_allowance_' . $this->id);
if ($limit === false) { // 如果不存在 返回默认速率
$limit = 500;
Yii::$app->getCache()->set('rateLimiter_allowance_' . $this->id, $limit);
}
$time = Yii::$app->getCache()->get('rateLimiter_allowance_updated_at_' . $this->id);
if ($time === false) {
$time = time();
Yii::$app->getCache()->set('rateLimiter_allowance_updated_at_' . $this->id, $time);
}
return [$limit, $time];
}
/**
* 实现保存用户剩余请求数接口
* @param \yii\web\Request $request 当前请求
* @param \yii\base\Action $action 执行的动作
* @param int $allowance 剩余的允许的请求次数.
* @param int $timestamp 最后一次速率限制检查时间戳.
*/
public function saveAllowance($request, $action, $allowance, $timestamp)
{
Yii::$app->getCache()->set('rateLimiter_allowance_' . $this->id, $allowance);
Yii::$app->getCache()->set('rateLimiter_allowance_updated_at_' . $this->id, $timestamp);
}
/**
* 登录成功后事件处理器
* @param object $event 事件对象
* @return bool
*/
public static function afterLoginHandler(&$event)
{
return true; // todo
}
}