feat:增加Token管理类

This commit is contained in:
妙码生花 2022-02-26 01:09:03 +08:00
parent c2c4326d7b
commit 84efe593f5
10 changed files with 386 additions and 8 deletions

View File

@ -1,9 +1,12 @@
<?php
declare (strict_types = 1);
declare (strict_types=1);
namespace app\admin\controller;
use bd\Random;
use app\common\controller\Backend;
use app\common\facade\Token;
use think\facade\Db;
class Index extends Backend
{
@ -14,16 +17,17 @@ class Index extends Backend
public function login()
{
$url = $this->request->get('url', '/admin');
$url = $this->request->get('url', '/admin');
$token = Random::uuid();
// Db::name
// 检查登录态
// 检查提交
if ($this->request->isPost()) {
$username = $this->request->post('username');
$password = $this->request->post('password');
$username = $this->request->post('username');
$password = $this->request->post('password');
$keeplogin = $this->request->post('keeplogin');
$token = $this->request->post('__token__');
print_r($username);
}

View File

@ -0,0 +1,23 @@
<?php
namespace app\common\facade;
use app\common\library\token\Driver;
use think\Facade;
/**
* Token 门面类
* @see Driver
* @method Driver get(string $token) static 获取 token 的数据
* @method Driver set(string $token, string $type, int $user_id, int $expire = 0) static 设置 token
* @method Driver check(string $token, string $type, int $user_id) static 检查token是否有效
* @method Driver delete(string $token) static 删除一个token
* @method Driver clear(string $type, int $user_id) static 清理一个用户的所有token
*/
class Token extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\library\Token';
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace app\common\library;
use app\common\library\token\Driver;
use think\helper\Arr;
use think\Manager;
/**
* Token 管理类
* @see Manager 用来加载驱动
* @mixin Driver
*/
class Token extends Manager
{
protected $namespace = '\\app\\common\\library\\token\\driver\\';
/**
* 默认驱动
* @return string
*/
public function getDefaultDriver()
{
return $this->getConfig('default');
}
public function getConfig(string $name = null, $default = null)
{
if (!is_null($name)) {
return $this->app->config->get('buildadmin.token.' . $name, $default);
}
return $this->app->config->get('buildadmin.token');
}
/**
* 获取驱动配置
* @param string $store
* @param string $name
* @param null $default
* @return array
*/
public function getStoreConfig(string $store, string $name = null, $default = null)
{
if ($config = $this->getConfig("stores.{$store}")) {
return Arr::get($config, $name, $default);
}
throw new \InvalidArgumentException("Store [$store] not found.");
}
protected function resolveType(string $name)
{
return $this->getStoreConfig($name, 'type', 'mysql');
}
protected function resolveConfig(string $name)
{
return $this->getStoreConfig($name);
}
public function store(string $name = null)
{
return $this->driver($name);
}
public function set(string $token, string $type, int $user_id, int $expire = null): bool
{
return $this->store()->set($token, $type, $user_id, $expire);
}
public function get(string $token): array
{
return $this->store()->get($token);
}
public function check(string $token, string $type, int $user_id): bool
{
return $this->store()->check($token, $type, $user_id);
}
public function delete(string $token): bool
{
return $this->store()->delete($token);
}
public function clear(string $type, int $user_id): bool
{
return $this->store()->clear($type, $user_id);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace app\common\library\token;
use think\facade\Config;
/**
* Token 驱动抽象类
*/
abstract class Driver
{
/**
* @var null 具体驱动的句柄 Mysql|Redis
*/
protected $handler = null;
/**
* @var array 配置数据
*/
protected $options = [];
/**
* 设置 token
* @param string $token Token
* @param string $type Type:admin|user
* @param int $user_id 用户ID
* @param int $expire 过期时间
* @return bool
*/
abstract function set(string $token, string $type, int $user_id, int $expire = 0): bool;
/**
* 获取 token 的数据
* @param string $token Token
* @return array
*/
abstract function get(string $token): array;
/**
* 检查token是否有效
* @param string $token
* @param string $type
* @param int $user_id
* @return bool
*/
abstract function check(string $token, string $type, int $user_id): bool;
/**
* 删除一个token
* @param string $token
* @return bool
*/
abstract function delete(string $token): bool;
/**
* 清理一个用户的所有token
* @param string $type
* @param int $user_id
* @return bool
*/
abstract function clear(string $type, int $user_id): bool;
/**
* 返回句柄对象
* @access public
* @return object
*/
public function handler()
{
return $this->handler;
}
/**
* @param string $token
* @return string
*/
protected function getEncryptedToken(string $token): string
{
$config = Config::get('buildadmin.token');
return hash_hmac($config['algo'], $token, $config['key']);
}
/**
* @param int $expiretime
* @return int
*/
protected function getExpiredIn(int $expiretime): int
{
return $expiretime ? max(0, $expiretime - time()) : 365 * 86400;
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace app\common\library\token\driver;
use app\common\library\token\Driver;
use think\facade\Db;
/**
* @see Driver
*/
class Mysql extends Driver
{
/**
* 默认配置
* @var array
*/
protected $options = [];
/**
* 构造函数
* @param array $options 参数
* @access public
*/
public function __construct($options = [])
{
if (!empty($options)) {
$this->options = array_merge($this->options, $options);
}
if ($this->options['name']) {
$this->handler = Db::connect($this->options['name'])->name($this->options['table']);
} else {
$this->handler = Db::name($this->options['table']);
}
}
public function set(string $token, string $type, int $user_id, int $expire = null): bool
{
if (is_null($expire)) {
$expire = $this->options['expire'];
}
$expiretime = $expire !== 0 ? time() + $expire : 0;
$token = $this->getEncryptedToken($token);
$this->handler->insert(['token' => $token, 'type' => $type, 'user_id' => $user_id, 'createtime' => time(), 'expiretime' => $expiretime]);
return true;
}
public function get(string $token): array
{
$data = $this->handler->where('token', $this->getEncryptedToken($token))->find();
if ($data) {
if (!$data['expiretime'] || $data['expiretime'] > time()) {
//返回未加密的token给客户端使用
$data['token'] = $token;
//返回剩余有效时间
$data['expires_in'] = $this->getExpiredIn($data['expiretime']);
return $data;
} else {
self::delete($token);
}
}
return [];
}
public function check(string $token, string $type, int $user_id): bool
{
$data = $this->get($token);
return $data && $data['type'] == $type && $data['user_id'] == $user_id;
}
public function delete(string $token): bool
{
$this->handler->where('token', $this->getEncryptedToken($token))->delete();
return true;
}
public function clear(string $type, int $user_id): bool
{
$this->handler->where('type', $type)->where('user_id', $user_id)->delete();
return true;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace app\common\library\token\driver;
use app\common\library\token\Driver;
class Redis
{
/**
* 默认配置
* @var array
*/
protected $options = [];
public function __construct($options = [])
{
if (!empty($options)) {
$this->options = array_merge($this->options, $options);
}
echo '待完善' . PHP_EOL;
echo '---Redis配置信息---' . PHP_EOL;
print_r($this->options);
}
}

View File

@ -19,4 +19,36 @@ return [
'web-install' => 'cd ../web && cnpm install',
'web-build' => 'cd ../web && cnpm run build:online',
],
'token' => [
// 默认驱动方式
'default' => 'mysql',
// 加密key
'key' => 'tcbDgmqLVzuAdNH39o0QnhOisvSCFZ7I',
// 加密方式
'algo' => 'ripemd160',
// 驱动
'stores' => [
'mysql' => [
'type' => 'Mysql',
// 留空表示使用默认的 Mysql 数据库,也可以填写其他数据库连接配置的`name`
'name' => '',
// 存储token的表名
'table' => 'token',
// 默认 token 有效时间
'expire' => 2592000,
],
'redis' => [
'type' => 'Redis',
'host' => '127.0.0.1',
'port' => 6379,
'password' => '',
'select' => 0,
'timeout' => 0,
'expire' => 0,
'persistent' => false,
'userprefix' => 'up:',
'tokenprefix' => 'tp:',
]
]
]
];

23
extend/bd/Random.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace bd;
class Random
{
/**
* 获取全球唯一标识
* @return string
*/
public static function uuid()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000
) . substr(md5(uniqid(mt_rand(), true)), 0, 12);
}
}

View File

@ -1,9 +1,9 @@
import Axios from '/@/utils/axios'
export function login(params: object) {
export function login(params: object, method: 'get'|'post') {
return Axios.request({
url: '/index.php/admin/index/login',
method: 'post',
method: method,
data: params
})
}

View File

@ -151,6 +151,8 @@ const rules = reactive({
],
})
var token = ''
onMounted(() => {
setTimeout(() => {
pageBubble.init()
@ -163,6 +165,10 @@ onMounted(() => {
} else if (form.code === '') {
vm.ctx.$refs.code.focus()
}
login({}, 'get').then((res) => {
})
})
onBeforeUnmount(() => {
@ -178,7 +184,7 @@ const onSubmit = (formEl: InstanceType<typeof ElForm> | undefined) => {
formEl.validate((valid) => {
if (valid) {
form.loading = true
login(form)
login(form, 'post')
.then((res) => {
console.log(res)
})