277 lines
9.7 KiB
PHP
277 lines
9.7 KiB
PHP
<?php
|
||
|
||
namespace app\models;
|
||
|
||
use Yii;
|
||
use app\components\FlashStorage;
|
||
use app\components\SiteHelper;
|
||
|
||
/**
|
||
* This is the model class for table "{{%user_token}}".
|
||
*
|
||
* @property int $id ID
|
||
* @property int $cx_mch_id 平台商户ID
|
||
* @property int $user_id 用户ID
|
||
* @property int $type 类型
|
||
* @property string $token 令牌
|
||
* @property int $expire_time 失效时间
|
||
* @property int $status 状态,0=未验证,1=验证通过,2=验证未通过,3=已失效
|
||
* @property int $is_delete 是否删除,0=否,1=是
|
||
* @property int $created_at 添加时间
|
||
*/
|
||
class UserToken extends \yii\db\ActiveRecord
|
||
{
|
||
const TYPE_WXMP_LOGIN = 0; //微信小程序登录token
|
||
const TYPE_WXOA_LOGIN = 1; //微信公众号登录token
|
||
const TYPE_APP_LOGIN = 2; //APP登录token
|
||
const TYPE_H5_LOGIN = 3; //H5登录token
|
||
|
||
|
||
const STATUS_WAITING = 0; //待验证
|
||
const STATUS_SUCCESS = 1; //验证通过
|
||
const STATUS_FAILED = 2; //验证未通过
|
||
const STATUS_VALIDATE = 3; //验证中
|
||
const STATUS_INVALID = 4; //失效
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public static function tableName()
|
||
{
|
||
return '{{%user_token}}';
|
||
}
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public function rules()
|
||
{
|
||
return [
|
||
[['cx_mch_id', 'user_id', 'type', 'expire_time', 'status', 'is_delete', 'created_at'], 'integer'],
|
||
[['token'], 'required'],
|
||
[['token'], 'string', 'max' => 128],
|
||
];
|
||
}
|
||
|
||
/**
|
||
* {@inheritdoc}
|
||
*/
|
||
public function attributeLabels()
|
||
{
|
||
return [
|
||
'id' => 'ID',
|
||
'cx_mch_id' => '平台商户ID',
|
||
'user_id' => '用户ID',
|
||
'type' => '类型',
|
||
'token' => '令牌',
|
||
'expire_time' => '失效时间',
|
||
'status' => '状态,0=未验证,1=验证通过,2=验证未通过,3=已失效',
|
||
'is_delete' => '是否删除,0=否,1=是',
|
||
'created_at' => '添加时间',
|
||
];
|
||
}
|
||
|
||
public function beforeSave($insert) {
|
||
if(parent::beforeSave($insert)){
|
||
if($this->isNewRecord){
|
||
}
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成token
|
||
* @param integer $type 类型
|
||
* @param integer $len token长度
|
||
* @param integer $retry 重试次数
|
||
*/
|
||
public static function generate($type = self::TYPE_WXAPP_LOGIN, $len = 12, $retry = 3, $cx_mch_id = 0)
|
||
{
|
||
$cache_key = "u_t_g_{$cx_mch_id}";
|
||
$cache_val = FlashStorage::getCache($cache_key);
|
||
if($cache_val !== false){
|
||
sleep(1);
|
||
$retry -= 1;
|
||
return $retry >= 0 ? self::generate($type, $len, $retry, $cx_mch_id) : null;
|
||
}
|
||
FlashStorage::setCache($cache_key, $cache_key);
|
||
$token = null;
|
||
while(true){
|
||
$token = self::_generate($len);
|
||
$exists = UserToken::find()->where(['type' => $type, 'token' => $token, 'is_delete' => 0, 'cx_mch_id' => $cx_mch_id])->exists();
|
||
if(!$exists){
|
||
FlashStorage::deleteCache($cache_key);
|
||
break;
|
||
}
|
||
}
|
||
return $token;
|
||
}
|
||
|
||
/**
|
||
* 生成指定长度的token
|
||
* @param integer $len 长度
|
||
*/
|
||
public static function _generate($len = 12)
|
||
{
|
||
$chars = "qwertyuiopasdfghjklzxcvbnm1234567890MNBVCXZASDFGHJKLPIUIYTREWQ";
|
||
$max = strlen($chars) - 1;
|
||
$token = "";
|
||
for($i = 0 ; $i < $len; $i++){
|
||
$start = mt_rand(0, $max);
|
||
$token .= $chars[$start];
|
||
}
|
||
//并发情况生成唯一token
|
||
$cache_key = "u_t_n_g_no_{$token}";
|
||
$cache_val = FlashStorage::getCache($cache_key);
|
||
if($cache_val !== false){
|
||
usleep(500);
|
||
return self::_generate($len);
|
||
}
|
||
FlashStorage::setCache($cache_key, $cache_key,60);
|
||
|
||
return $token;
|
||
}
|
||
|
||
/**
|
||
* 保存token
|
||
* @param string $token token
|
||
* @param integer $type token类型
|
||
* @param integer $expire_time token有效时长,单位秒
|
||
* @param integer $user_id 用户ID
|
||
* @param integer $cx_mch_id 平台商户ID
|
||
*/
|
||
public static function saveUserToken($token, $type, $expire_time, $user_id = 0, $cx_mch_id = 0)
|
||
{
|
||
$timestamp = time();
|
||
$model = new UserToken();
|
||
$model->cx_mch_id = $cx_mch_id;
|
||
$model->type = $type;
|
||
$model->token = $token;
|
||
$model->user_id = $user_id;
|
||
$model->expire_time = $timestamp + $expire_time;
|
||
$model->status = self::STATUS_WAITING;
|
||
$model->is_delete = 0;
|
||
$model->created_at = $timestamp;
|
||
if(!$model->save()){
|
||
return SiteHelper::getModelError($model);
|
||
}
|
||
return [
|
||
'code' => 0,
|
||
'msg' => 'ok',
|
||
'data' => [
|
||
'token' => $token
|
||
]
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 清除已经失效的token
|
||
*/
|
||
public static function expiresHandler($cx_mch_id = null, $limit = 200)
|
||
{
|
||
$ids = UserToken::find()
|
||
->where([
|
||
'is_delete' => 0
|
||
])
|
||
->andWhere([
|
||
'<',
|
||
'expire_time',
|
||
time()
|
||
])
|
||
->andFilterWhere([
|
||
'cx_mch_id' => $cx_mch_id
|
||
])
|
||
->select('id')->limit($limit)->column();
|
||
UserToken::updateAll(['is_delete' => 1],[
|
||
'is_delete' => 0,
|
||
'id' => $ids
|
||
]);
|
||
}
|
||
|
||
public static function getOauthConf($type)
|
||
{
|
||
switch ($type){
|
||
//微信小程序登录
|
||
case 0:
|
||
return [
|
||
'access_token_key' => '405nr7', //@CX INIT PARAM
|
||
'refresh_token_key' => 'I0gd86', //@CX INIT PARAM
|
||
'access_token_max_age' => 60*60*24*30, //@CX INIT PARAM
|
||
'refresh_token_max_age' => 2592000, //@CX INIT PARAM
|
||
'token_len' => 12, //@CX INIT PARAM 生成token长度
|
||
'token_retry' => 3, //@CX INIT PARAM 生成token重试次数
|
||
];
|
||
//微信公众号登录
|
||
case 1:
|
||
return [
|
||
'access_token_key' => '02LZh7', //@CX INIT PARAM
|
||
'refresh_token_key' => 'x2Ch1B', //@CX INIT PARAM
|
||
'access_token_max_age' => 7200, //@CX INIT PARAM
|
||
'refresh_token_max_age' => 2592000, //@CX INIT PARAM
|
||
'token_len' => 13, //@CX INIT PARAM 生成token长度
|
||
'token_retry' => 3, //@CX INIT PARAM 生成token重试次数
|
||
];
|
||
//APP登录
|
||
case 2:
|
||
return [
|
||
'access_token_key' => '01LZh7', //@CX INIT PARAM
|
||
'refresh_token_key' => 'x1Ch1B', //@CX INIT PARAM
|
||
'access_token_max_age' => 7200, //@CX INIT PARAM
|
||
'refresh_token_max_age' => 2592000, //@CX INIT PARAM
|
||
'token_len' => 14, //@CX INIT PARAM 生成token长度
|
||
'token_retry' => 3, //@CX INIT PARAM 生成token重试次数
|
||
];
|
||
//H5登录
|
||
case 3:
|
||
return [
|
||
'access_token_key' => '01LZh7', //@CX INIT PARAM
|
||
'refresh_token_key' => 'x1Ch1B', //@CX INIT PARAM
|
||
'access_token_max_age' => 86400, //@CX INIT PARAM
|
||
'refresh_token_max_age' => 2592000, //@CX INIT PARAM
|
||
'token_len' => 14, //@CX INIT PARAM 生成token长度
|
||
'token_retry' => 3, //@CX INIT PARAM 生成token重试次数
|
||
];
|
||
//@TODO 扩展,默认微信小程序登录
|
||
default :
|
||
return [
|
||
'access_token_key' => '405nr7', //@CX INIT PARAM
|
||
'refresh_token_key' => 'I0gd86', //@CX INIT PARAM
|
||
'access_token_max_age' => 60*60*24*30, //@CX INIT PARAM
|
||
'refresh_token_max_age' => 2592000, //@CX INIT PARAM
|
||
'token_len' => 12, //@CX INIT PARAM 生成token长度
|
||
'token_retry' => 3, //@CX INIT PARAM 生成token重试次数
|
||
];
|
||
|
||
}
|
||
}
|
||
|
||
public static function getTypeByPlatform($platform)
|
||
{
|
||
switch ($platform){
|
||
case 'wxmp':
|
||
return UserToken::TYPE_WXMP_LOGIN;
|
||
case 'wxoa':
|
||
return UserToken::TYPE_WXOA_LOGIN;
|
||
case 'app':
|
||
return UserToken::TYPE_APP_LOGIN;
|
||
case 'h5':
|
||
return UserToken::TYPE_H5_LOGIN;
|
||
//@TODO 其它平台
|
||
default :
|
||
return UserToken::TYPE_WXMP_LOGIN;
|
||
}
|
||
}
|
||
|
||
public static function destory($user_id, $type, $cx_mch_id)
|
||
{
|
||
UserToken::updateAll(['is_delete' => 1],[
|
||
'is_delete' => 0,
|
||
'user_id' => $user_id,
|
||
'cx_mch_id' => $cx_mch_id,
|
||
'type' => $type
|
||
]);
|
||
}
|
||
}
|