ThinkPHP Auth授权权限+菜单生成

浏览:893 发布日期:2018/07/11 分类:功能实现
ThinkPHP Auth授权功能
之前用授权都是自己瞎写的,用起来很麻烦,而且复用性极差,几乎每个项目要重新写一个,最近新写了一个可以复用的;
里面使用了think-queue,在用户登录的时候将登录信息异步写入!
修改分页类,往里面增加了跳页;

验证规则支持多个,例如: admin/user/add|admin/user/checkUsername 根据竖线分割
所有规则不区分大小写(在里面做了一些处理);

例如我们添加用户的时候需要验证用户的手机号码或者用户名是否存在,可以使用ajax异步去验证,之前用的需要将异步验证的规则写到新的字段里面;
这个里面一个规则搞定多个!

后台导航菜单,根据所添加时的规则来生成,用户拥有权限则会显示该菜单!


用户登录:表单Token,可以选择自动登录,
后续要加登录失败次数限制,以及自动登录时的环境检测,多端登录逼下线等!
对于代码有不合理的地方希望大家提出来!

auth.php 配置文件<?php
/**
 * User: 李昊天
 * Date: 18/7/10
 * Time: 上午7:30
 * Email: haotian0607@gmail.com
 */
return [
    'not_auth_tip' => '无权限操作!', //无权限的提示信息
    'is_cache' => true,        //是否将规则缓存
    'expire' => 0,              //缓存时间
    'prefix' => '',             //缓存前缀
    'name' => 'user_auth',      //缓存key
    'exclude_rule' => [         //不验证权限的url
        'admin/main/index', //后台首页
        'admin/main/welcome',   //后台欢迎页
        'admin/main/clearCache',   //清除缓存
    ],
];
Auth核心类代码:<?php
/**
 * User: 李昊天
 * Date: 18/7/10
 * Time: 上午6:03
 * Email: haotian0607@gmail.com
 */

namespace auth;

use think\Db;
use think\facade\Cache;

class Auth
{
    private static $rulesData = [];
    protected $config = [
        'is_cache' => false,        //是否将规则缓存
        'expire' => 0,              //缓存时间
        'prefix' => '',             //缓存前缀
        'name' => 'user_auth',      //缓存key
    ];

    public function __construct($config = [])
    {
        $this->config = array_merge($this->config, $config);
    }

    public function check($rules = '', $uid = 0, $logic = 'OR')
    {

        //检测是否为超级管理员
        if (true === $this->checkIsSuper($uid)) return true;
        $userRules = $this->getUserRules($uid);

        foreach ($userRules as $key => $value) {
            if (strpos($value, '|')) {
                foreach (explode('|', $value) as $item) {
                    self::$rulesData[] = strtolower($item);   //规则转小写
                }
            } else {
                self::$rulesData[] = strtolower($value);    //规则转小写
            }
        }

        self::$rulesData = array_unique(self::$rulesData);  //数组去重

        array_walk($rules, function (&$value) {
            $value = strtolower($value);   //规则转小写
        });

        sort($rules);
        sort(self::$rulesData);
        switch (strtoupper($logic)) {
            case 'AND':
                // 用户规则包含全部的校验规则
                // 交集为需要校验的规则, 说明包含
                return $rules == array_intersect($rules, self::$rulesData);
                break;
            case 'OR':
            default:
                // 只要包含至少一个校验规则即可
                // 交集不为空即可.
                return !empty(array_intersect($rules, self::$rulesData));
                break;
        }
    }

    /**
     * 检测是否为超级管理员
     * @param int $uid
     * @return bool
     */
    private function checkIsSuper($uid = 0)
    {
        $key = $this->prefix . $this->name . $uid . 'checkSuper';
        if ($this->is_cache === true) {
            $result = Cache::get($key);
            if (false === $result) {
                $result = $this->getUserIsSuperData($uid);
                Cache::set($key, $result, $this->expire);
            }
        } else {
            $result = $this->getUserIsSuperData($uid);
        }

        if ($result > 0) return true;
    }

    /**
     * 获取用户全部权限
     * @param int $uid
     * @return array
     */
    private function getUserRules($uid = 0)
    {
        if ($this->is_cache === true) {
            $key = $this->prefix . $this->name . $uid . 'getUserRules';
            $result = Cache::get($key);
            if (false === $result) {
                $result = $this->getUserRulesData($uid);
                Cache::set($key, $result, $this->expire);
            }
        } else {
            $result = $this->getUserRulesData($uid);
        }

        return $result;
    }

    /**
     * @param int $uid
     * @return array|mixed|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getMenu($uid = 0)
    {
        if (true === $this->is_cache) {
            $key = $this->prefix . $this->name . $uid . 'getMenu';
            $result = Cache::get($key);
            if (false === $result) {
                if (true === $this->checkIsSuper($uid)) {
                    //如果是超级管理员就获取全部规则作为菜单
                    $result = $this->getSuperMenuData();
                } else {
                    $result = $this->getUserMenuData($uid);
                }
                Cache::set($key, $result, $this->expire);
            }
        } else {
            if (true === $this->checkIsSuper($uid)) {
                //如果是超级管理员就获取全部规则作为菜单
                $result = $this->getSuperMenuData();
            } else {
                $result = $this->getUserMenuData($uid);
            }
        }
        return $result;
    }

    /**
     * 获取超级管理员菜单 超级管理员获取所有可以生成菜单的权限
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function getSuperMenuData()
    {
        return Db::name('auth_rule')->field('id,pid,rule_name,menu_name,menu_route')->order('sort', 'desc')->distinct(true)->where('is_menu', 1)->select();
    }

    /**
     * 获取用户菜单  获取用户对于的权限 作为菜单
     * @param int $uid
     * @return array|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function getUserMenuData($uid = 0)
    {
        return Db::name('auth_group_user')->alias('agu')->field('ar.id,ar.rule_name,ar.menu_name,ar.menu_route,ar.pid')->join('auth_group ag', 'ag.id=agu.gid')->join('auth_group_rule agr', 'agr.gid=ag.id')->join('auth_rule ar', 'ar.id=agr.rid')->where('agu.uid', $uid)->where('ar.is_menu', 1)->distinct(true)->select();
    }

    /**
     * 获取数据
     * @param int $uid
     * @return array
     */
    private function getUserRulesData($uid = 0)
    {
        return Db::name('auth_group_user')
            ->alias('agu')
            ->join('auth_group ag', 'ag.id=agu.gid')
            ->join('auth_group_rule agr', 'agr.gid=ag.id')
            ->join('auth_rule ar', 'ar.id=agr.rid')
            ->where('agu.uid', $uid)
            ->column('ar.rule_node');
    }

    /**
     * 检测是否为超级管理员
     * @param int $uid
     * @return float|string
     */
    private function getUserIsSuperData($uid = 0)
    {
        return Db::name('auth_group_user')->alias('agu')->join('auth_group ag', 'ag.id=agu.gid')->where('agu.uid', $uid)->where('ag.is_super', 1)->count('ag.id');
    }

    /**
     * 使用 $this->name 获取配置
     * @access public
     * @param  string $name 配置名称
     * @return mixed    配置值
     */
    public function __get($name)
    {
        return $this->config[$name];
    }

    /**
     * 检查配置
     * @access public
     * @param  string $name 配置名称
     * @return bool
     */
    public function __isset($name)
    {
        return isset($this->config[$name]);
    }
}



后台体验地址:https://admin.dreamcreating.cn/admin/login.shtml
账号和密码:18888888888

使用的时候需要在控制台执行(unix系统): nohup php think queue:work --queue saveLoginLog --tries 5 --sleep 3 --daemon 1>queue.log 2>&1 &windows 系统请大家自己查找一下方法;
该代码可能不适合在php版本 <7的环境下使用
现在的体验例子中使用的是:php7.2.+,ThinkPHP5.1.18+Nginx1.4+MySql5.7+Redis4.0

开启缓存后会生成菜单以及权限的缓存,在测试的时候可以将配置文件中的缓存关闭!
评论( 相关
后面还有条评论,点击查看>>