From cb05c2d4870f2a4a647763910bd4522a03daa3c6 Mon Sep 17 00:00:00 2001
From: 15090180611 <215509543@qq.com>
Date: Fri, 28 Mar 2025 18:06:59 +0800
Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=80=80=E5=87=BAapi?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
application/admin/view/command/add.html | 1 +
application/adminapi/behavior/AdminLog.php | 14 ++
application/adminapi/controller/Admin.php | 100 +++++++++
application/adminapi/library/Auth.php | 47 +++-
application/adminapi/model/Admin.php | 118 ++++++++++
application/adminapi/model/AdminLog.php | 119 +++++++++++
application/adminapi/tags.php | 18 ++
application/common/controller/AdminApi.php | 238 ++++++++++++++++++++-
8 files changed, 650 insertions(+), 5 deletions(-)
create mode 100644 application/adminapi/behavior/AdminLog.php
create mode 100644 application/adminapi/controller/Admin.php
create mode 100644 application/adminapi/model/Admin.php
create mode 100644 application/adminapi/model/AdminLog.php
create mode 100644 application/adminapi/tags.php
diff --git a/application/admin/view/command/add.html b/application/admin/view/command/add.html
index 2180096..b2b330f 100644
--- a/application/admin/view/command/add.html
+++ b/application/admin/view/command/add.html
@@ -353,6 +353,7 @@
+
diff --git a/application/adminapi/behavior/AdminLog.php b/application/adminapi/behavior/AdminLog.php
new file mode 100644
index 0000000..f2563ae
--- /dev/null
+++ b/application/adminapi/behavior/AdminLog.php
@@ -0,0 +1,14 @@
+isPost() && config('fastadmin.auto_record_log')) {
+ \app\adminapi\model\AdminLog::record();
+ }
+ }
+}
diff --git a/application/adminapi/controller/Admin.php b/application/adminapi/controller/Admin.php
new file mode 100644
index 0000000..a280f9b
--- /dev/null
+++ b/application/adminapi/controller/Admin.php
@@ -0,0 +1,100 @@
+model = new AdminModel;
+ parent::_initialize();
+
+ $auth = $this->auth;
+ //监听注册登录退出的事件
+ Hook::add('admin_login_successed', function ($user) use ($auth) {
+ $expire = input('post.keeplogin') ? 30 * 86400 : 0;
+ Cookie::set('adminid', $user->id, $expire);
+ Cookie::set('admintoken', $auth->getToken(), $expire);
+ });
+ Hook::add('admin_register_successed', function ($user) use ($auth) {
+ Cookie::set('adminid', $user->id);
+ Cookie::set('admintoken', $auth->getToken());
+ });
+ Hook::add('admin_delete_successed', function ($user) use ($auth) {
+ Cookie::delete('adminid');
+ Cookie::delete('admintoken');
+ });
+ Hook::add('admin_logout_successed', function ($user) use ($auth) {
+ Cookie::delete('adminid');
+ Cookie::delete('admintoken');
+ });
+
+
+ }
+
+
+
+ /**
+ * 管理员登录
+ *
+ * @ApiMethod (POST)
+ * @ApiParams (name="account", type="string", required=true, description="账号")
+ * @ApiParams (name="password", type="string", required=true, description="密码")
+ */
+ public function login()
+ {
+ $account = $this->request->post('account');
+ $password = $this->request->post('password');
+ if (!$account || !$password) {
+ $this->error(__('Invalid parameters'));
+ }
+ $ret = $this->auth->login($account, $password);
+ if ($ret) {
+ $data = ['userinfo' => $this->auth->getUserinfo()];
+ $this->success(__('Logged in successful'), $data);
+ } else {
+ $this->error($this->auth->getError());
+ }
+ }
+
+
+
+ /**
+ * 退出登录
+ * @ApiMethod (POST)
+ */
+ public function logout()
+ {
+// //设置contenttype不为表单格式防止触发宝塔防火墙
+// header('Content-Type:application/json; charset=utf-8');
+ if (!$this->request->isPost()) {
+ $this->error(__('Invalid parameters'));
+ }
+// $password = $this->request->post('datatime');
+
+ $this->auth->logout();
+ $this->success(__('Logout successful'));
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/application/adminapi/library/Auth.php b/application/adminapi/library/Auth.php
index a93f12d..744329d 100644
--- a/application/adminapi/library/Auth.php
+++ b/application/adminapi/library/Auth.php
@@ -1,6 +1,6 @@
rules) {
return $this->rules;
}
- $group = $this->_user->groups;
- if (!$group) {
+ $groups = $this->_user->groups;
+ if (!$groups) {
return [];
}
- $rules = explode(',', $group->rules);
+ $rules = [];
+ foreach ($groups as $group){
+ $rules = array_merge($rules, explode(',', $group->rules));
+ }
+
$this->rules = AuthRule::where('status', 'normal')->where('id', 'in', $rules)->field('id,pid,rule_name,name,title,ismenu')->select();
return $this->rules;
}
@@ -462,4 +467,38 @@ class Auth
return $this->_error ? __($this->_error) : '';
}
+
+
+ /**
+ * 获得面包屑导航
+ * @param string $path
+ * @return array
+ */
+ public function getBreadCrumb($path = '')
+ {
+ if ($this->breadcrumb || !$path) {
+ return $this->breadcrumb;
+ }
+ $titleArr = [];
+ $menuArr = [];
+ $urlArr = explode('/', $path);
+ foreach ($urlArr as $index => $item) {
+ $pathArr[implode('/', array_slice($urlArr, 0, $index + 1))] = $index;
+ }
+ if (!$this->rules && $this->id) {
+ $this->getRuleList();
+ }
+ foreach ($this->rules as $rule) {
+ if (isset($pathArr[$rule['name']])) {
+ $rule['title'] = __($rule['title']);
+ $rule['url'] = url($rule['name']);
+ $titleArr[$pathArr[$rule['name']]] = $rule['title'];
+ $menuArr[$pathArr[$rule['name']]] = $rule;
+ }
+ }
+ ksort($menuArr);
+ $this->breadcrumb = $menuArr;
+ return $this->breadcrumb;
+ }
+
}
\ No newline at end of file
diff --git a/application/adminapi/model/Admin.php b/application/adminapi/model/Admin.php
new file mode 100644
index 0000000..81f336f
--- /dev/null
+++ b/application/adminapi/model/Admin.php
@@ -0,0 +1,118 @@
+column("group_id");
+ if(!$group_ids)return [];
+
+ $groups = \app\admin\model\api\AuthGroup::where("id","in",$group_ids)->select();
+ return $groups;
+ }
+
+
+
+
+
+
+ public static function init()
+ {
+ self::beforeWrite(function ($row) {
+ $changed = $row->getChangedData();
+ //如果修改了用户或或密码则需要重新登录
+ if (isset($changed['username']) || isset($changed['password']) || isset($changed['salt'])) {
+ $row->token = '';
+ }
+ });
+ }
+
+ public function getAddressCityList(){
+ return SearchCity::column("address_city","id");
+ }
+
+
+ public static function getHaveShopId($adminId){
+ $admin = self::get($adminId);
+ if(!$admin)throw new \Exception("管理员不存在");
+ $area_json = $admin->area_json;
+ $shop_id = "*";
+ if($area_json){
+ $shop_id = [];
+ $searchCity = SearchCity::where("id","in",$area_json)->select();
+ foreach ($searchCity as $item){
+ $province = $item->province;
+ $city = $item->city;
+ $district = $item->district;
+ //查询在该区域的店铺id
+ $manystoreShop = new ManystoreShop;
+ if($province)$manystoreShop = $manystoreShop->where("province",$province);
+ if($city)$manystoreShop = $manystoreShop->where("city",$city);
+ if($district)$manystoreShop = $manystoreShop->where("district",$district);
+ $shop_id = array_merge($shop_id,$manystoreShop->column("id"));
+ }
+ }
+ return $shop_id;
+ }
+
+ public static function getHaveCity($adminId){
+ $provinces = $citys = $districts = $address_citys = [];
+ $admin = self::get($adminId);
+ if(!$admin)return compact("provinces","citys","districts","address_citys");
+ $area_json = $admin->area_json;
+
+ if($area_json){
+ $searchCity = SearchCity::where("id","in",$area_json)->select();
+ foreach ($searchCity as $item){
+ $address_citys[] = $item->address_city;
+ $province = $item->province;
+ if($province)$provinces[] = $province;
+ $city = $item->city;
+ if($city)$citys[] = $city;
+ $district = $item->district;
+ if($district)$districts[] = $district;
+ }
+ }
+ if(!$provinces)$provinces="*";
+ if(!$citys)$citys="*";
+ if(!$districts)$districts="*";
+ if(!$address_citys)$address_citys="*";
+ return compact("provinces","citys","districts","address_citys");
+ }
+
+
+
+ public static function checkAuthMsg($adminId){
+ ["provinces" =>$provinces,"citys"=> $citys, "districts"=>$districts,"address_citys"=>$address_citys] = self::getHaveCity($adminId);
+ if(is_array($address_citys))$address_citys = implode(",",$address_citys);
+ //必要信息已完善
+ return '
+ 您当前的区域管理权限为: '.$address_citys.' (能管理该区域下的机构信息,如果是*则不限制)
';
+
+ }
+
+
+}
diff --git a/application/adminapi/model/AdminLog.php b/application/adminapi/model/AdminLog.php
new file mode 100644
index 0000000..37da958
--- /dev/null
+++ b/application/adminapi/model/AdminLog.php
@@ -0,0 +1,119 @@
+isLogin() ? $auth->id : 0;
+ $username = $auth->isLogin() ? $auth->username : __('Unknown');
+
+ // 设置过滤函数
+ request()->filter('trim,strip_tags,htmlspecialchars');
+ $modulename = request()->module();
+ $controllername = Loader::parseName(request()->controller());
+ $actionname = strtolower(request()->action());
+ $path = $modulename. '/' . str_replace('.', '/', $controllername) . '/' . $actionname;
+ if (self::$ignoreRegex) {
+ foreach (self::$ignoreRegex as $index => $item) {
+ if (preg_match($item, $path)) {
+ return;
+ }
+ }
+ }
+ $content = $content ?: self::$content;
+ if (!$content) {
+ $content = request()->param('') ?: file_get_contents("php://input");
+ $content = self::getPureContent($content);
+ }
+ $title = $title ?: self::$title;
+ if (!$title) {
+ $title = [];
+ $breadcrumb = Auth::instance()->getBreadcrumb($path);
+ foreach ($breadcrumb as $k => $v) {
+ $title[] = $v['title'];
+ }
+ $title = implode(' / ', $title);
+ }
+ self::create([
+ 'title' => $title,
+ 'content' => !is_scalar($content) ? json_encode($content, JSON_UNESCAPED_UNICODE) : $content,
+ 'url' => substr(xss_clean(strip_tags(request()->url())), 0, 1500),
+ 'admin_id' => $admin_id,
+ 'username' => $username,
+ 'useragent' => substr(request()->server('HTTP_USER_AGENT'), 0, 255),
+ 'ip' => xss_clean(strip_tags(request()->ip()))
+ ]);
+ }
+
+ /**
+ * 获取已屏蔽关键信息的数据
+ * @param $content
+ * @return array
+ */
+ protected static function getPureContent($content)
+ {
+ if (!is_array($content)) {
+ return $content;
+ }
+ foreach ($content as $index => &$item) {
+ if (preg_match("/(password|salt|token)/i", $index)) {
+ $item = "***";
+ } else {
+ if (is_array($item)) {
+ $item = self::getPureContent($item);
+ }
+ }
+ }
+ return $content;
+ }
+
+ public function admin()
+ {
+ return $this->belongsTo('Admin', 'admin_id')->setEagerlyType(0);
+ }
+}
diff --git a/application/adminapi/tags.php b/application/adminapi/tags.php
new file mode 100644
index 0000000..882fdfb
--- /dev/null
+++ b/application/adminapi/tags.php
@@ -0,0 +1,18 @@
+
+// +----------------------------------------------------------------------
+// 应用行为扩展定义文件
+return [
+ // 应用结束
+ 'app_end' => [
+ 'app\\adminapi\\behavior\\AdminLog',
+ ],
+];
diff --git a/application/common/controller/AdminApi.php b/application/common/controller/AdminApi.php
index 26266a9..8295574 100644
--- a/application/common/controller/AdminApi.php
+++ b/application/common/controller/AdminApi.php
@@ -3,7 +3,7 @@
namespace app\common\controller;
-use app\common\library\Auth;
+use app\adminapi\library\Auth;
use app\common\library\Virtual;
use think\Config;
use think\exception\HttpResponseException;
@@ -125,6 +125,242 @@ class AdminApi
//移除HTML标签
$this->request->filter('trim,strip_tags,htmlspecialchars');
+
+ $this->auth = Auth::instance();
+
+ $modulename = $this->request->module();
+ $controllername = Loader::parseName($this->request->controller());
+ $actionname = strtolower($this->request->action());
+ // token
+ $token = $this->request->server('HTTP_ADMINTOKEN', $this->request->request('admintoken', \think\Cookie::get('admintoken')));
+
+ $path = $modulename. '/' .str_replace('.', '/', $controllername) . '/' . $actionname;
+ // 设置当前请求的URI
+ $this->auth->setRequestUri($path);
+
+ // 检测是否需要验证登录
+ if (!$this->auth->match($this->noNeedLogin)) {
+ //初始化
+ $this->auth->init($token);
+ //检测是否登录
+ if (!$this->auth->isLogin()) {
+ $this->error(__('Please login first'), ['errcode'=>30002], 401);
+ }
+ // 判断是否需要验证权限
+ if (!$this->auth->match($this->noNeedRight)) {
+ // 判断控制器和方法判断是否有对应权限
+ if (!$this->auth->check($path)) {
+ $this->error(__('You have no permission'), null, 403);
+ }
+ }
+ } else {
+ // 如果有传递token才验证是否登录状态
+ if ($token) {
+ $this->auth->init($token);
+ }
+ }
+
+
+ $upload = \app\common\model\Config::upload();
+
+ // 上传信息配置后
+ Hook::listen("upload_config_init", $upload);
+
+ Config::set('upload', array_merge(Config::get('upload'), $upload));
+
+ // 加载当前控制器语言包
+ $this->loadlang($controllername);
+// Virtual::visitNnmberUpdate();
}
+
+ /**
+ * 加载语言文件
+ * @param string $name
+ */
+ protected function loadlang($name)
+ {
+ $name = Loader::parseName($name);
+ $name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
+ $lang = $this->request->langset();
+ $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
+ Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('.', '/', $name) . '.php');
+ }
+
+
+ /**
+ * 操作成功返回的数据
+ * @param string $msg 提示信息
+ * @param mixed $data 要返回的数据
+ * @param int $code 错误码,默认为1
+ * @param string $type 输出类型
+ * @param array $header 发送的 Header 信息
+ */
+ protected function success($msg = '', $data = null, $code = 1, $type = null, array $header = [])
+ {
+ $this->result($msg, $data, $code, $type, $header);
+ }
+
+ /**
+ * 操作失败返回的数据
+ * @param string $msg 提示信息
+ * @param mixed $data 要返回的数据
+ * @param int $code 错误码,默认为0
+ * @param string $type 输出类型
+ * @param array $header 发送的 Header 信息
+ */
+ protected function error($msg = '', $data = null, $code = 0, $type = null, array $header = [])
+ {
+ $this->result($msg, $data, $code, $type, $header);
+ }
+
+ /**
+ * 返回封装后的 API 数据到客户端
+ * @access protected
+ * @param mixed $msg 提示信息
+ * @param mixed $data 要返回的数据
+ * @param int $code 错误码,默认为0
+ * @param string $type 输出类型,支持json/xml/jsonp
+ * @param array $header 发送的 Header 信息
+ * @return void
+ * @throws HttpResponseException
+ */
+ protected function result($msg, $data = null, $code = 0, $type = null, array $header = [])
+ {
+ $result = [
+ 'code' => $code,
+ 'msg' => $msg,
+ 'time' => Request::instance()->server('REQUEST_TIME'),
+ 'data' => $data,
+ ];
+ // 如果未设置类型则使用默认类型判断
+ $type = $type ? : $this->responseType;
+
+ if (isset($header['statuscode'])) {
+ $code = $header['statuscode'];
+ unset($header['statuscode']);
+ } else {
+ //未设置状态码,根据code值判断
+ $code = $code >= 1000 || $code < 200 ? 200 : $code;
+ }
+ $response = Response::create($result, $type, $code)->header($header);
+ throw new HttpResponseException($response);
+ }
+
+
+ /**
+ * 前置操作
+ * @access protected
+ * @param string $method 前置操作方法名
+ * @param array $options 调用参数 ['only'=>[...]] 或者 ['except'=>[...]]
+ * @return void
+ */
+ protected function beforeAction($method, $options = [])
+ {
+ if (isset($options['only'])) {
+ if (is_string($options['only'])) {
+ $options['only'] = explode(',', $options['only']);
+ }
+
+ if (!in_array($this->request->action(), $options['only'])) {
+ return;
+ }
+ } elseif (isset($options['except'])) {
+ if (is_string($options['except'])) {
+ $options['except'] = explode(',', $options['except']);
+ }
+
+ if (in_array($this->request->action(), $options['except'])) {
+ return;
+ }
+ }
+
+ call_user_func([$this, $method]);
+ }
+
+ /**
+ * 设置验证失败后是否抛出异常
+ * @access protected
+ * @param bool $fail 是否抛出异常
+ * @return $this
+ */
+ protected function validateFailException($fail = true)
+ {
+ $this->failException = $fail;
+
+ return $this;
+ }
+
+
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $data 数据
+ * @param string|array $validate 验证器名或者验证规则数组
+ * @param array $message 提示信息
+ * @param bool $batch 是否批量验证
+ * @param mixed $callback 回调方法(闭包)
+ * @return array|string|true
+ * @throws ValidateException
+ */
+ protected function validate($data, $validate, $message = [], $batch = false, $callback = null)
+ {
+ if (is_array($validate)) {
+ $v = Loader::validate();
+ $v->rule($validate);
+ } else {
+ // 支持场景
+ if (strpos($validate, '.')) {
+ list($validate, $scene) = explode('.', $validate);
+ }
+
+ $v = Loader::validate($validate);
+
+ !empty($scene) && $v->scene($scene);
+ }
+
+ // 批量验证
+ if ($batch || $this->batchValidate) {
+ $v->batch(true);
+ }
+ // 设置错误信息
+ if (is_array($message)) {
+ $v->message($message);
+ }
+ // 使用回调验证
+ if ($callback && is_callable($callback)) {
+ call_user_func_array($callback, [$v, &$data]);
+ }
+
+ if (!$v->check($data)) {
+ if ($this->failException) {
+ throw new ValidateException($v->getError());
+ }
+
+ return $v->getError();
+ }
+
+ return true;
+ }
+
+
+ /**
+ * 刷新Token
+ */
+ protected function token()
+ {
+ $token = $this->request->param('__token__');
+
+ //验证Token
+ if (!Validate::make()->check(['__token__' => $token], ['__token__' => 'require|token'])) {
+ $this->error(__('Token verification error'), ['__token__' => $this->request->token()]);
+ }
+
+ //刷新Token
+ $this->request->token();
+ }
+
+
+
}
\ No newline at end of file