mirror of https://gitee.com/karson/fastadmin.git
581 lines
16 KiB
PHP
581 lines
16 KiB
PHP
<?php
|
|
|
|
namespace app\common\library;
|
|
|
|
use app\common\model\User;
|
|
use app\common\model\UserThird;
|
|
use fast\Random;
|
|
use fast\ucenter\client\Client;
|
|
use think\Cookie;
|
|
use think\Db;
|
|
use think\Exception;
|
|
use think\Validate;
|
|
|
|
/**
|
|
* Auth类
|
|
*/
|
|
class Auth
|
|
{
|
|
|
|
const ERR_ACCOUNT_IS_INCORRECT = 'Account is incorrect';
|
|
const ERR_ACCOUNT_NOT_EXIST = 'Account not exist';
|
|
const ERR_USERNAME_IS_INCORRECT = 'Username is incorrect';
|
|
const ERR_EMAIL_IS_INCORRECT = 'Email is incorrect';
|
|
const ERR_PASSWORD_IS_INCORRECT = 'Password is incorrect';
|
|
const ERR_USERNAME_OR_PASSWORD_IS_INCORRECT = 'Username or password is incorrect';
|
|
const ERR_USERNAME_ALREADY_EXIST = 'Username already exist';
|
|
const ERR_EMAIL_ALREADY_EXIST = 'Email already exist';
|
|
const ERR_MOBILE_ALREADY_EXIST = 'Mobile already exist';
|
|
const ERR_ACCOUNT_IS_LOCKED = 'Account is locked';
|
|
const ERR_USERNAME_OR_PASSWORD_IS_MODIFIED = 'Username or password is modified';
|
|
const ERR_YOU_ARE_NOT_LOGGED_IN = 'You are not logged in';
|
|
const ERR_ACCOUNT_ALREADY_LOGGED_IN_AT_ANOTHER_PLACE = 'Account already logged in at another';
|
|
|
|
protected static $instance = null;
|
|
private $_error = '';
|
|
private $_logined = FALSE;
|
|
private $user = NULL;
|
|
private $keeptime = 0;
|
|
private $requestUri = '';
|
|
|
|
public function __construct()
|
|
{
|
|
$this->user = new User;
|
|
}
|
|
|
|
/**
|
|
* 初始化
|
|
* @param array $options 参数
|
|
* @return Auth
|
|
*/
|
|
public static function instance($options = [])
|
|
{
|
|
if (is_null(self::$instance))
|
|
{
|
|
self::$instance = new static($options);
|
|
}
|
|
|
|
return self::$instance;
|
|
}
|
|
|
|
public function __get($name)
|
|
{
|
|
return $this->check() ? $this->user->$name : NULL;
|
|
}
|
|
|
|
public function __call($name, $arguments)
|
|
{
|
|
return call_user_func_array([$this->user, $name], $arguments);
|
|
}
|
|
|
|
/**
|
|
* 注册用户
|
|
*
|
|
* @param string $username 用户名
|
|
* @param string $password 密码
|
|
* @param string $email 邮箱
|
|
* @param string $mobile 手机号
|
|
* @param string $extend 扩展参数
|
|
* @return boolean
|
|
*/
|
|
public function register($username, $password, $email = '', $mobile = '', $extend = [], $keeptime = 0, $sync = TRUE)
|
|
{
|
|
$rule = [
|
|
'username' => 'require|length:6,30',
|
|
'password' => 'require|length:6,30',
|
|
'email' => 'email',
|
|
'mobile' => 'regex:/^1\d{10}$/',
|
|
];
|
|
|
|
$msg = [
|
|
'username.require' => __('Username can not be empty'),
|
|
'username.length' => __('Username must be 6 to 30 characters'),
|
|
'password.require' => __('Password can not be empty'),
|
|
'password.length' => __('Password must be 6 to 30 characters'),
|
|
'email' => __('Email is incorrect'),
|
|
'mobile' => __('Mobile is incorrect'),
|
|
];
|
|
$data = [
|
|
'username' => $username,
|
|
'password' => $password,
|
|
'email' => $email,
|
|
'mobile' => $mobile,
|
|
];
|
|
$validate = new Validate($rule, $msg);
|
|
$result = $validate->check($data);
|
|
if (!$result)
|
|
{
|
|
$this->setError($validate->getError());
|
|
return FALSE;
|
|
}
|
|
|
|
// 检测用户名或邮箱、手机号是否存在
|
|
if (User::getByUsername($username))
|
|
{
|
|
$this->setError(__('Username already exist'));
|
|
return FALSE;
|
|
}
|
|
if ($email && User::getByEmail($email))
|
|
{
|
|
$this->setError(__('Email already exist'));
|
|
return FALSE;
|
|
}
|
|
if ($mobile && User::getByMobile($mobile))
|
|
{
|
|
$this->setError(__('Mobile already exist'));
|
|
return FALSE;
|
|
}
|
|
|
|
$ip = request()->ip();
|
|
$time = time();
|
|
$params = array_merge($data, [
|
|
'nickname' => $username,
|
|
'salt' => Random::alnum(),
|
|
'jointime' => $time,
|
|
'joinip' => $ip,
|
|
'logintime' => $time,
|
|
'loginip' => $ip,
|
|
'prevtime' => $time,
|
|
'status' => 'normal'
|
|
]);
|
|
$params['password'] = $this->getEncryptPassword($password, $params['salt']);
|
|
$params = array_merge($params, $extend);
|
|
|
|
////////////////同步到Ucenter////////////////
|
|
if (defined('UC_STATUS') && UC_STATUS && $sync)
|
|
{
|
|
$uc = new Client();
|
|
$user_id = $uc->uc_user_register($username, $password, $email);
|
|
// 如果小于0则说明发生错误
|
|
if ($user_id <= 0)
|
|
{
|
|
$this->setError($user_id > -4 ? self::ERR_USERNAME_IS_INCORRECT : self::ERR_EMAIL_IS_INCORRECT);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
$params['id'] = $user_id;
|
|
}
|
|
}
|
|
|
|
//账号注册时需要开启事务,避免出现垃圾数据
|
|
Db::startTrans();
|
|
try
|
|
{
|
|
$ret = $this->user->save($params);
|
|
Db::commit();
|
|
|
|
// 此时的Model中只包含部分数据
|
|
$this->user = $this->user->get($this->user->id);
|
|
|
|
$this->keeptime($keeptime);
|
|
return $this->syncLogin();
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
Db::rollback();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 用户登录
|
|
*
|
|
* @param string $account 账号,用户名、邮箱、手机号
|
|
* @param string $password 密码
|
|
* @param int $keeptime 有效时长,默认为浏览器关闭
|
|
* @return array
|
|
*/
|
|
public function login($account, $password, $keeptime = 0, $sync = TRUE)
|
|
{
|
|
$field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username');
|
|
$user = $this->user->get([$field => $account]);
|
|
if ($user)
|
|
{
|
|
if ($user->status != 'normal')
|
|
{
|
|
$this->setError(self::ERR_ACCOUNT_IS_LOCKED);
|
|
return FALSE;
|
|
}
|
|
if ($user->password != $this->getEncryptPassword($password, $user->salt))
|
|
{
|
|
$this->setError(self::ERR_PASSWORD_IS_INCORRECT);
|
|
return FALSE;
|
|
}
|
|
|
|
$this->user = $user;
|
|
|
|
// 设置登录有效时长
|
|
$this->keeptime($keeptime);
|
|
|
|
return $this->syncLogin($sync);
|
|
}
|
|
else
|
|
{
|
|
$this->setError(self::ERR_ACCOUNT_IS_INCORRECT);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 注销登录退出
|
|
* @return bool
|
|
*/
|
|
public function logout($token = NULL)
|
|
{
|
|
//设置登录标识
|
|
$this->_logined = FALSE;
|
|
$token = is_null($token) ? Cookie::get('token') : $token;
|
|
Token::delete($token);
|
|
Cookie::delete('user_id');
|
|
//Cookie::del('username');
|
|
Cookie::delete('token');
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* 生成Token
|
|
* @return string
|
|
*/
|
|
public function token()
|
|
{
|
|
//$token = Encrypt::aesEncode($this->keeptime . '|' . $expiretime, Config::get('encrypt', 'aes_key'), TRUE);
|
|
$token = Random::uuid();
|
|
Token::set($token, $this->user->id, $this->keeptime);
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* 初始化
|
|
*
|
|
* @param int $user_id 会员ID,默认从Cookie中取
|
|
* @param string $token 会员Token,默认从Cookie中取
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function init($user_id = NULL, $token = NULL)
|
|
{
|
|
$user_id = $user_id ? $user_id : Cookie::get('user_id');
|
|
$user_id = intval($user_id);
|
|
if ($user_id > 0)
|
|
{
|
|
if ($this->_error)
|
|
return FALSE;
|
|
$user = $this->get($user_id);
|
|
if (!$user)
|
|
{
|
|
$this->setError(self::ERR_ACCOUNT_NOT_EXIST);
|
|
return FALSE;
|
|
}
|
|
if ($user['status'] != 'normal')
|
|
{
|
|
$this->setError(self::ERR_ACCOUNT_IS_LOCKED);
|
|
return FALSE;
|
|
}
|
|
$token = $token ? $token : Cookie::get('token');
|
|
if (!Token::check($token))
|
|
{
|
|
return FALSE;
|
|
}
|
|
$this->user = $user;
|
|
$this->_logined = TRUE;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
$this->setError(self::ERR_YOU_ARE_NOT_LOGGED_IN);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检测是否登录
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function check()
|
|
{
|
|
return $this->_logined;
|
|
}
|
|
|
|
/**
|
|
* 检测是否登录
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function isLogin()
|
|
{
|
|
return $this->check();
|
|
}
|
|
|
|
/**
|
|
* 获取当前请求的URI
|
|
* @return string
|
|
*/
|
|
public function getRequestUri()
|
|
{
|
|
return $this->requestUri;
|
|
}
|
|
|
|
/**
|
|
* 设置当前请求的URI
|
|
* @param string $uri
|
|
*/
|
|
public function setRequestUri($uri)
|
|
{
|
|
$this->requestUri = $uri;
|
|
}
|
|
|
|
/**
|
|
* 第三方登录
|
|
* @param string $platform
|
|
* @param array $params
|
|
* @param int $keeptime
|
|
* @return boolean
|
|
*/
|
|
public function connect($platform, $params = [], $keeptime = 0)
|
|
{
|
|
$time = time();
|
|
$values = [
|
|
'platform' => $platform,
|
|
'openid' => $params['openid'],
|
|
'openname' => isset($params['userinfo']['nickname']) ? $params['userinfo']['nickname'] : '',
|
|
'access_token' => $params['access_token'],
|
|
'refresh_token' => $params['refresh_token'],
|
|
'expires_in' => $params['expires_in'],
|
|
'logintime' => $time,
|
|
'expiretime' => $time + $params['expires_in'],
|
|
];
|
|
|
|
$this->keeptime($keeptime);
|
|
$userthird = UserThird::get(['platform' => $platform, 'openid' => $params['openid']]);
|
|
if ($userthird)
|
|
{
|
|
$this->user = $this->user->get($userthird['user_id']);
|
|
if (!$this->user)
|
|
{
|
|
return FALSE;
|
|
}
|
|
$userthird->save($values);
|
|
return $this->syncLogin();
|
|
}
|
|
else
|
|
{
|
|
// 先随机一个用户名,随后再变更为u+数字id
|
|
$username = Random::alnum(20);
|
|
$password = Random::alnum(6);
|
|
// 默认注册一个会员
|
|
$result = $this->register($username, $password, '', '', [], $keeptime);
|
|
if (!$result)
|
|
{
|
|
return FALSE;
|
|
}
|
|
$userarr = ['username' => 'u' . $this->user->id];
|
|
if (isset($params['userinfo']['nickname']))
|
|
$userarr['nickname'] = $params['userinfo']['nickname'];
|
|
if (isset($params['userinfo']['avatar']))
|
|
$userarr['avatar'] = $params['userinfo']['avatar'];
|
|
|
|
// 更新会员资料
|
|
$this->user->save($userarr);
|
|
|
|
// 保存第三方信息
|
|
$values['user_id'] = $this->user->id;
|
|
UserThird::create($values);
|
|
|
|
// 写入登录Cookies和Token
|
|
$this->writeStatus();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 删除一个指定会员
|
|
* @param int $user_id
|
|
* @param bool $sync 是否同步删除
|
|
*/
|
|
public function delete($user_id, $sync = TRUE)
|
|
{
|
|
$user = $this->user->get($user_id);
|
|
if (!$user)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
////////////////同步到Ucenter////////////////
|
|
if (defined('UC_STATUS') && UC_STATUS && $sync)
|
|
{
|
|
$uc = new Client();
|
|
$re = $uc->uc_user_delete($user['id']);
|
|
// 如果小于0则说明发生错误
|
|
if ($re <= 0)
|
|
{
|
|
$this->setError(self::ERR_ACCOUNT_IS_LOCKED);
|
|
return FALSE;
|
|
}
|
|
}
|
|
// 调用事务删除账号
|
|
$result = Db::transaction(function($db) use($user_id)
|
|
{
|
|
// 删除会员
|
|
User::destroy($user_id);
|
|
|
|
// 删除会员第三方登录
|
|
UserThird::destroy($user_id);
|
|
});
|
|
|
|
return $result ? TRUE : FALSE;
|
|
}
|
|
|
|
/**
|
|
* 直接登录账号
|
|
* @param int $user_id
|
|
* @param boolean $sync
|
|
* @return boolean
|
|
*/
|
|
public function direct($user_id, $sync = TRUE)
|
|
{
|
|
$this->user = $this->user->get($user_id);
|
|
if ($this->user)
|
|
{
|
|
$this->syncLogin($sync);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取密码加密方式
|
|
* @param string $password
|
|
* @param string $salt
|
|
* @return string
|
|
*/
|
|
public function getEncryptPassword($password, $salt = '')
|
|
{
|
|
return md5(md5($password) . $salt);
|
|
}
|
|
|
|
/**
|
|
* 同步登录信息
|
|
* @param int $sync 是否同步登录到UC
|
|
* @return boolean
|
|
*/
|
|
protected function syncLogin($sync = TRUE)
|
|
{
|
|
////////////////同步到Ucenter////////////////
|
|
if (defined('UC_STATUS') && UC_STATUS && $sync)
|
|
{
|
|
$uc = new Client();
|
|
$re = $uc->uc_user_login($this->user->id, $this->user->password . '#split#' . $this->user->salt, 3);
|
|
// 如果小于0则说明发生错误
|
|
if ($re <= 0)
|
|
{
|
|
$this->setError(self::ERR_USERNAME_OR_PASSWORD_IS_INCORRECT);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//增加登录次数和设置最后登录时间
|
|
$this->user->save([
|
|
'prevtime' => $this->user->logintime,
|
|
'logintime' => time(),
|
|
'loginip' => request()->ip(),
|
|
]);
|
|
|
|
// 写入登录Cookies和Token
|
|
$this->writeStatus();
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* 写入登录态和Cookie
|
|
*
|
|
* @param int $keeptime
|
|
*/
|
|
protected function writeStatus()
|
|
{
|
|
//设置登录标识
|
|
$this->_logined = TRUE;
|
|
|
|
$token = $this->token();
|
|
Cookie::set('user_id', $this->user->id, $this->keeptime);
|
|
Cookie::set('username', $this->user->username, 86400 * 365);
|
|
//加密安全字符
|
|
Cookie::set('token', $token, $this->keeptime);
|
|
$this->setError('');
|
|
}
|
|
|
|
/**
|
|
* 设置会话有效时间
|
|
* @param int $keeptime 默认为永久
|
|
*/
|
|
public function keeptime($keeptime = 0)
|
|
{
|
|
$this->keeptime = $keeptime;
|
|
}
|
|
|
|
/**
|
|
* 渲染用户数据
|
|
* @param array $datalist
|
|
* @param array $fields
|
|
* @param string $fieldkey
|
|
* @param string $renderkey
|
|
* @return array
|
|
*/
|
|
public function render(&$datalist, $fields = [], $fieldkey = 'user_id', $renderkey = 'userinfo')
|
|
{
|
|
$fields = !$fields ? ['id', 'nickname', 'level', 'avatar'] : (is_array($fields) ? $fields : explode(',', $fields));
|
|
$ids = [];
|
|
foreach ($datalist as $k => $v)
|
|
{
|
|
if (!isset($v[$fieldkey]))
|
|
continue;
|
|
$ids[] = $v[$fieldkey];
|
|
}
|
|
$list = [];
|
|
if ($ids)
|
|
{
|
|
if (!in_array('id', $fields))
|
|
{
|
|
$fields[] = 'id';
|
|
}
|
|
$ids = array_unique($ids);
|
|
$selectlist = User::where('id', 'in', $ids)->column($fields);
|
|
foreach ($selectlist as $k => $v)
|
|
{
|
|
$list[$v['id']] = $v;
|
|
}
|
|
}
|
|
foreach ($datalist as $k => &$v)
|
|
{
|
|
$v[$renderkey] = isset($list[$v[$fieldkey]]) ? $list[$v[$fieldkey]] : NULL;
|
|
}
|
|
unset($v);
|
|
return $datalist;
|
|
}
|
|
|
|
/**
|
|
* 设置错误信息
|
|
*
|
|
* @param $error
|
|
*/
|
|
public function setError($error)
|
|
{
|
|
$this->_error = $error;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* 获取错误信息
|
|
* @return string
|
|
*/
|
|
public function getError()
|
|
{
|
|
return __($this->_error);
|
|
}
|
|
|
|
}
|