保护/限制用户组功能的良好做法


Good practice to protect / limit functions to user groups

我有一个扩展到多个类文件的大项目。这个项目是为了赶在最后期限前完成的。这对项目的安全性造成了影响。简单地说,理论上任何人都可以在我的项目中调用AJAX脚本并让它运行,因为脚本中的函数不知道用户权限。当然,我会检查我所有的AJAX PHP脚本,看看用户是否登录。

这里有一个例子:

// Update user information. This script is called with jQuery AJAX:
<?php
include('../../../config/config.php');
require_once('classes/Autoloader.php');
$iris = new IRIS();
if( !$iris->UUID() ){
    die( "Unauthorized access! ");
}
$result = array('success'=>true);
$users = new users();
try {
    $res = $users->createUser();
    $result = array( 'success' => true, 'result' => $_POST );
}
catch(Exception $e){
    $result = array( 'error' => true, 'errmsg' => $e->getMessage() );
}
echo json_encode( $result );

我有3个用户类:"Admin"、"client"、"employee"。现在理论上,所有这些都可以调用这个php脚本,并修改用户,即使只有管理员应该有权这样做。用户在数据库中指定了权限参数,我在项目中用一个常量定义了这个参数:

define('USER_AUTH_LEVEL', $_SESSION['auth_level']);

我知道我可以更新每个AJAX PHP文件并设置:

if( USER_AUTH_LEVEL !== 1 ) { die( 'You do not have access' ); }

但我想做的是保护我的类的所有或部分函数。比方说:

class IRIS {
    public function doSomething(){
         // $function_access not defined, accessable by all
    }
    public function doSomethingAdmin(){
        $function_access = 1;
         // Should be limited to admins
    }
    public function doSomethingClient(){
         $function_access = 2;
         // Should be limited to clients
    }
}

我想要实现的是一个每当函数运行时都会运行的脚本,无论函数所在的类是什么。此脚本应检查是否设置了参数$function_access。如果是,则应将其与当前登录用户的权限级别进行比较。如果不匹配,则函数应中断。如果根本没有定义,任何人都可以运行该函数。

有人对此有办法吗?我一片空白。

在调用任何函数之前,都需要调用一些函数。为此,请使用__call方法:

class IRIS extends Access {
    /* other methods here */
    // list all methods to allow some access levels.
    public function accessControll() {
       return [
          parent::ADMIN => ['doSomethingAdmin', 'doSomethingElseAdmin'],
          parent::USER => ['doSomething', 'doSomethingElse'],
       ];
    }
}
abstract class Access {
    // access levels defines
    const ADMIN = 1, USER = 2;
    public function __call($method, $arguments) {
        $accessLevel = -1;
        // get access level of current method
        foreach ($this->accessControll() as $key => $group) {
            if (in_array($method, $group)) {
                $accessLevel = $key;
                break;
            }
        }
        if (USER_AUTH_LEVEL !== $accessLevel) {
            throw new Exception('You do not have access');
            // OR header('HTTP/1.0 401 not authorized');
        }
    }
    // abstract, so every class, that extends it must have this method.
    abstract public function accessControll();
}