前言
ThinkAdmin是基于thinkphp开发的后台管理系统,较为容易上手。
它有完整的商城系统和用户管理系统。
介绍在文档里有我就不过多赘述,这里主要整理一些使用时的情况
目录结构
.
├─ app 应用基础目录
│ ├─ admin 后台应用目录
│ │ ├─ controller 应用控制器
│ │ ├─ route 应用路由配置
│ │ ├─ view 应用视图目录
│ │ └─ sys.php 模块注册文件
│ ├─ index 默认应用入口
│ │ └─ controller 控制器目录
│ └─ wechat 微信应用目录
│ ├─ command 应用指令目录
│ ├─ controller 控制器目录
│ ├─ service 应用服务目录
│ ├─ view 应用视图目录
│ └─ sys.php 模块注册文件
├─ config 全局配置目录
│ ├─ app.php 应用配置
│ ├─ cache.php 缓存配置
│ ├─ cookie.php Cookie 配置
│ ├─ database.php 数据库配置
│ ├─ filesystem.php 文件磁盘配置
│ ├─ lang.php 系统多语言配置
│ ├─ log.php 全局日志配置
│ ├─ route.php URL和路由配置
│ ├─ session.php Session 配置
│ └─ view.php 视图配置
├─ public 网站开放目录
│ ├─ static 静态资源目录
│ │ ├─ plugs 后台应用插件
│ │ └─ theme 后台应用主题
│ ├─ upload 上传存储目录
│ ├─ index.php 网站访问入口
│ ├─ router.php 网站测试入口
│ └─ think 指令访问入口
├─ runtime 应用的运行时目录,需要可写权限
│ ├─ admin 系统应用运行目录
│ ├─ cache 系统默认缓存目录
│ ├─ log 系统指令运行日志
│ ├─ session Session 会话缓存
│ └─ wechat 微信应用运行目录
├─ safefile 安全文件上传目录
└─ vendor Composer 安装的第三方类库目录
用户相关
对于前端的一些接口都是放在data目录下的,请求头都需要添加api-type用于后续token验证
注册
/data/api.login/register
测试的时候直接将手机验证注释了
public function register()
{
$data = $this->_vali([
'region_province.default' => '',
'region_city.default' => '',
'region_area.default' => '',
'username.default' => '',
'phone.mobile' => '手机格式错误!',
'phone.require' => '手机不能为空!',
'verify.require' => '验证码不能为空!',
'password.require' => '登录密码不能为空!',
]);
//隐藏需要手机验证
// if (!MessageService::instance()->checkVerifyCode($data['verify'], $data['phone'])) {
// $this->error('手机短信验证失败!');
// }
$map = ['phone' => $data['phone'], 'deleted' => 0];
if (DataUser::mk()->where($map)->count() > 0) {
$this->error('手机号已注册,请使用其它手机号!');
}
$data['password'] = md5($data['password']);
$user = UserAdminService::set($map, $data, $this->type, true);
empty($user) ? $this->error('手机注册失败!') : $this->success('用户注册成功!', $user);
}
登录
登录主要用于获取token,有关个人用户的数据是需要token验证的
/data/api.login/in
public function in()
{
$data = $this->_vali([
'phone.mobile' => '手机号码格式错误!',
'phone.require' => '手机号码不能为空!',
'password.require' => '登录密码不能为空!',
]);
$map = ['deleted' => 0, 'phone' => $data['phone']];
$user = DataUser::mk()->where($map)->find();
if (empty($user)) $this->error('该手机号还没有注册哦!');
if (empty($user['status'])) $this->error('该用户账号状态异常!');
if (md5($data['password']) === $user['password']) {
$this->success('手机登录成功!', UserAdminService::set($map, [], $this->type, true));
} else {
$this->error('账号登录失败,请稍候再试!');
}
}
授权
查看Auth文件可知,初始化的时候需要传api-type判断类型
/**
* 控制器初始化
*/
protected function initialize()
{
// 接收接口类型
$this->type = $this->request->request('api');
$this->type = $this->type ?: $this->request->header('api-name');
$this->type = $this->type ?: $this->request->header('api-type');
// 检查接口类型
if (empty($this->type)) {
$this->error("未获取到接口类型字段!");
}
if (!isset(UserAdminService::TYPES[$this->type])) {
$this->error("接口类型[{$this->type}]未定义!");
}
// 获取用户数据
$this->user = $this->getUser();
$this->uuid = $this->user['id'] ?? '';
if (empty($this->uuid)) {
$this->error('用户登录失败!', '{-null-}', 401);
}
}
检测授权是需要api-token用来判断用户
protected function getUser(): array
{
try {
if (empty($this->uuid)) {
$token = input('token') ?: $this->request->header('api-token');
if (empty($token)) $this->error('登录认证TOKEN不能为空!');
[$state, $info, $this->uuid] = UserTokenService::instance()->check($this->type, $token);
if (empty($state)) $this->error($info, '{-null-}', 401);
}
return UserAdminService::instance()->get($this->uuid, $this->type);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
UserTokenService中检测token是否合规
public static function check(string $type, string $token, array $data = []): array
{
if (empty($data)) {
$map = ['type' => $type, 'token' => $token];
$data = DataUserToken::mk()->where($map)->find();
}
if (empty($data) || empty($data['uuid'])) {
return [0, '请重新登录,登录认证无效', 0, 0];
} elseif ($token !== 'token' && $data['time'] < time()) {
return [0, '请重新登录,登录认证失效', 0, 0];
} elseif ($token !== 'token' && $data['tokenv'] !== static::buildVerify()) {
return [0, '请重新登录,客户端已更换', 0, 0];
} else {
static::expire($type, $token);
return [1, '登录验证成功', $data['uuid'], $data['time']];
}
}
查询用户
/data/api.auth.center/get
用户的数据是从DataUser拿到的
<?php
namespace app\data\model;
use think\admin\Model;
/**
* 用户数据模型
* Class DataUser
* @package app\data\model
*/
class DataUser extends Model
{
}
对应数据表data_user
public static function get(int $uuid, string $type): array
{
$map = ['id' => $uuid, 'deleted' => 0];
$user = DataUser::mk()->where($map)->findOrEmpty();
if ($user->isEmpty()) throw new Exception('用户还没有注册!');
// 用户认证令牌处理
$map = ['uuid' => $uuid, 'type' => $type];
if (!($access = DataUserToken::mk()->where($map)->find())) {
[$state, $message, $access] = UserTokenService::token($uuid, $type);
if (empty($state) || empty($access)) throw new Exception($message);
}
$user['token'] = ['token' => $access['token'], 'expire' => $access['time']];
return $user->hidden(['deleted', 'password'])->toArray();
}