init
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
namespace plugin\admin\api;
|
||||
|
||||
use plugin\admin\app\model\Role;
|
||||
use plugin\admin\app\model\Rule;
|
||||
use support\exception\BusinessException;
|
||||
use function admin;
|
||||
|
||||
/**
|
||||
* 对外提供的鉴权接口
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
/**
|
||||
* 判断权限
|
||||
* 如果没有权限则抛出异常
|
||||
* @param string $controller
|
||||
* @param string $action
|
||||
* @return void
|
||||
* @throws \ReflectionException|BusinessException
|
||||
*/
|
||||
public static function access(string $controller, string $action)
|
||||
{
|
||||
$code = 0;
|
||||
$msg = '';
|
||||
if (!static::canAccess($controller, $action, $code, $msg)) {
|
||||
throw new BusinessException($msg, $code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否有权限
|
||||
* @param string $controller
|
||||
* @param string $action
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @return bool
|
||||
* @throws \ReflectionException|BusinessException
|
||||
*/
|
||||
public static function canAccess(string $controller, string $action, int &$code = 0, string &$msg = ''): bool
|
||||
{
|
||||
// 无控制器信息说明是函数调用,函数不属于任何控制器,鉴权操作应该在函数内部完成。
|
||||
if (!$controller) {
|
||||
return true;
|
||||
}
|
||||
// 获取控制器鉴权信息
|
||||
$class = new \ReflectionClass($controller);
|
||||
$properties = $class->getDefaultProperties();
|
||||
$noNeedLogin = $properties['noNeedLogin'] ?? [];
|
||||
$noNeedAuth = $properties['noNeedAuth'] ?? [];
|
||||
|
||||
// 不需要登录
|
||||
if (in_array($action, $noNeedLogin)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取登录信息
|
||||
$admin = admin();
|
||||
if (!$admin) {
|
||||
$msg = '请登录';
|
||||
// 401是未登录固定的返回码
|
||||
$code = 401;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 不需要鉴权
|
||||
if (in_array($action, $noNeedAuth)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 当前管理员无角色
|
||||
$roles = $admin['roles'];
|
||||
if (!$roles) {
|
||||
$msg = '无权限';
|
||||
$code = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 角色没有规则
|
||||
$rules = Role::whereIn('id', $roles)->pluck('rules');
|
||||
$rule_ids = [];
|
||||
foreach ($rules as $rule_string) {
|
||||
if (!$rule_string) {
|
||||
continue;
|
||||
}
|
||||
$rule_ids = array_merge($rule_ids, explode(',', $rule_string));
|
||||
}
|
||||
if (!$rule_ids) {
|
||||
$msg = '无权限';
|
||||
$code = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 超级管理员
|
||||
if (in_array('*', $rule_ids)){
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果action为index,规则里有任意一个以$controller开头的权限即可
|
||||
if (strtolower($action) === 'index') {
|
||||
$rule = Rule::where(function ($query) use ($controller, $action) {
|
||||
$controller_like = str_replace('\\', '\\\\', $controller);
|
||||
$query->where('key', 'like', "$controller_like@%")->orWhere('key', $controller);
|
||||
})->whereIn('id', $rule_ids)->first();
|
||||
if ($rule) {
|
||||
return true;
|
||||
}
|
||||
$msg = '无权限';
|
||||
$code = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查询是否有当前控制器的规则
|
||||
$rule = Rule::where(function ($query) use ($controller, $action) {
|
||||
$query->where('key', "$controller@$action")->orWhere('key', $controller);
|
||||
})->whereIn('id', $rule_ids)->first();
|
||||
|
||||
if (!$rule) {
|
||||
$msg = '无权限';
|
||||
$code = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace plugin\admin\api;
|
||||
|
||||
class Install
|
||||
{
|
||||
/**
|
||||
* 安装
|
||||
*
|
||||
* @param $version
|
||||
* @return void
|
||||
*/
|
||||
public static function install($version)
|
||||
{
|
||||
// 导入菜单
|
||||
Menu::import(static::getMenus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 卸载
|
||||
*
|
||||
* @param $version
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall($version)
|
||||
{
|
||||
// 删除菜单
|
||||
foreach (static::getMenus() as $menu) {
|
||||
Menu::delete($menu['name']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*
|
||||
* @param $from_version
|
||||
* @param $to_version
|
||||
* @param $context
|
||||
* @return void
|
||||
*/
|
||||
public static function update($from_version, $to_version, $context = null)
|
||||
{
|
||||
// 删除不用的菜单
|
||||
if (isset($context['previous_menus'])) {
|
||||
static::removeUnnecessaryMenus($context['previous_menus']);
|
||||
}
|
||||
// 导入新菜单
|
||||
Menu::import(static::getMenus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新前数据收集等
|
||||
*
|
||||
* @param $from_version
|
||||
* @param $to_version
|
||||
* @return array|array[]
|
||||
*/
|
||||
public static function beforeUpdate($from_version, $to_version)
|
||||
{
|
||||
// 在更新之前获得老菜单,通过context传递给 update
|
||||
return ['previous_menus' => static::getMenus()];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function getMenus()
|
||||
{
|
||||
clearstatcache();
|
||||
if (is_file($menu_file = __DIR__ . '/../config/menu.php')) {
|
||||
$menus = include $menu_file;
|
||||
return $menus ?: [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除不需要的菜单
|
||||
*
|
||||
* @param $previous_menus
|
||||
* @return void
|
||||
*/
|
||||
public static function removeUnnecessaryMenus($previous_menus)
|
||||
{
|
||||
$menus_to_remove = array_diff(Menu::column($previous_menus, 'name'), Menu::column(static::getMenus(), 'name'));
|
||||
foreach ($menus_to_remove as $name) {
|
||||
Menu::delete($name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace plugin\admin\api;
|
||||
|
||||
use plugin\admin\app\model\Rule;
|
||||
|
||||
/**
|
||||
* 对外提供的菜单接口
|
||||
*/
|
||||
class Menu
|
||||
{
|
||||
|
||||
/**
|
||||
* 根据key获取菜单
|
||||
* @param $key
|
||||
* @return array
|
||||
*/
|
||||
public static function get($key)
|
||||
{
|
||||
$menu = Rule::where('key', $key)->first();
|
||||
return $menu ? $menu->toArray() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id获得菜单
|
||||
* @param $id
|
||||
* @return array
|
||||
*/
|
||||
public static function find($id): array
|
||||
{
|
||||
return Rule::find($id)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加菜单
|
||||
* @param array $menu
|
||||
* @return int
|
||||
*/
|
||||
public static function add(array $menu)
|
||||
{
|
||||
$item = new Rule;
|
||||
foreach ($menu as $key => $value) {
|
||||
$item->$key = $value;
|
||||
}
|
||||
$item->save();
|
||||
return $item->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入菜单
|
||||
* @param array $menu_tree
|
||||
* @return void
|
||||
*/
|
||||
public static function import(array $menu_tree)
|
||||
{
|
||||
if (is_numeric(key($menu_tree)) && !isset($menu_tree['key'])) {
|
||||
foreach ($menu_tree as $item) {
|
||||
static::import($item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$children = $menu_tree['children'] ?? [];
|
||||
unset($menu_tree['children']);
|
||||
if ($old_menu = Menu::get($menu_tree['key'])) {
|
||||
$pid = $old_menu['id'];
|
||||
Rule::where('key', $menu_tree['key'])->update($menu_tree);
|
||||
} else {
|
||||
$pid = static::add($menu_tree);
|
||||
}
|
||||
foreach ($children as $menu) {
|
||||
$menu['pid'] = $pid;
|
||||
static::import($menu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
* @param $key
|
||||
* @return void
|
||||
*/
|
||||
public static function delete($key)
|
||||
{
|
||||
$item = Rule::where('key', $key)->first();
|
||||
if (!$item) {
|
||||
return;
|
||||
}
|
||||
// 子规则一起删除
|
||||
$delete_ids = $children_ids = [$item['id']];
|
||||
while($children_ids) {
|
||||
$children_ids = Rule::whereIn('pid', $children_ids)->pluck('id')->toArray();
|
||||
$delete_ids = array_merge($delete_ids, $children_ids);
|
||||
}
|
||||
Rule::whereIn('id', $delete_ids)->delete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取菜单中某个(些)字段的值
|
||||
* @param $menu
|
||||
* @param null $column
|
||||
* @param null $index
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function column($menu, $column = null, $index = null)
|
||||
{
|
||||
$values = [];
|
||||
if (is_numeric(key($menu)) && !isset($menu['key'])) {
|
||||
foreach ($menu as $item) {
|
||||
$values = array_merge($values, static::column($item, $column, $index));
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
$children = $menu['children'] ?? [];
|
||||
unset($menu['children']);
|
||||
if ($column === null) {
|
||||
if ($index) {
|
||||
$values[$menu[$index]] = $menu;
|
||||
} else {
|
||||
$values[] = $menu;
|
||||
}
|
||||
} else {
|
||||
if (is_array($column)) {
|
||||
$item = [];
|
||||
foreach ($column as $f) {
|
||||
$item[$f] = $menu[$f] ?? null;
|
||||
}
|
||||
if ($index) {
|
||||
$values[$menu[$index]] = $item;
|
||||
} else {
|
||||
$values[] = $item;
|
||||
}
|
||||
} else {
|
||||
$value = $menu[$column] ?? null;
|
||||
if ($index) {
|
||||
$values[$menu[$index]] = $value;
|
||||
} else {
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($children as $child) {
|
||||
$values = array_merge($values, static::column($child, $column, $index));
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
namespace plugin\admin\api;
|
||||
|
||||
use ReflectionException;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Webman\MiddlewareInterface;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
/**
|
||||
* 对外提供的鉴权中间件
|
||||
*/
|
||||
class Middleware implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* 鉴权
|
||||
* @param Request $request
|
||||
* @param callable $handler
|
||||
* @return Response
|
||||
* @throws ReflectionException
|
||||
* @throws BusinessException
|
||||
*/
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
$controller = $request->controller;
|
||||
$action = $request->action;
|
||||
|
||||
$code = 0;
|
||||
$msg = '';
|
||||
if (!Auth::canAccess($controller, $action, $code, $msg)) {
|
||||
if ($request->expectsJson()) {
|
||||
$response = json(['code' => $code, 'msg' => $msg, 'type' => 'error']);
|
||||
} else {
|
||||
if ($code === 401) {
|
||||
$response = admin_error_401_script();
|
||||
} else {
|
||||
$request->app = '';
|
||||
$request->plugin = 'admin';
|
||||
$response = view('common/error/403')->withStatus(403);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user