We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

How to correctly verify access and authorization?

Hello. I've encryption algo to create custom user string for user session cookie. It's very simple, and the cookie string has the format: ID.USERHASH.

And I've code such this for do my task.

// smth..

class AuthAccess
 {
    private $config;

    public function __construct($config)
    {
        $this->config = $config;
    }

    private function getAuthCookie()
    {
        return $this->cookies->get("USER_COOKIE");
    }

    private function createToken($userId) {
        // Encode token
        $data = $userId.$this->config->secret;

        $user = Users::findFirstById($userId);

        if ($user) {
            $hash   = hash_hmac("sha256", $data, $user->secretString);

            $user_token = $userId.".".$hash;
            $user_level = $user->level;
        }

        return [
            "token" => $user_token,
            "level" => $user_level,
        ];
    }

    public function checkAccess()
    {
        $token = $this->getAuthCookie();

        // hash.user_id
        if (!empty($token) && $token != "") {
            $split_token = explode(".", $token);

            $userId = $split_token[0];
            $hash  = $split_token[1];

            // Is the cookie valid?
            if ($expr >= $this->getTime()) {
                $rightToken = $this->createToken($userId);

                if ($token === $rightToken["token"]) {
                    return $rightToken["level"];
                }
            }
        }

        return false;
    }

    // ACL Checls, etc.
}

But how can I do this right with such checks, acl and etc.? Make it so that you can avoid duplication of code and dubious links. Use components or plugins?

Tell me, if I incorrectly described the problem, and I'll describe it more correctly. Thanks a lot!

It looks like you've got the code to check if the user can access the system. What you need to do now is update checkAccess() to make sure the user has the correct access level. I'd suggest have the method accept an integer parameter which is the current required level. This level can be determined from a config file or from the ACL component. Then, rather than returning the current access level, that method can just return TRUE or FALSE.

I would double-check your code - I think this line:

$user_token = $userId.".".$hash2;

should be

$user_token = $userId.".".$key;

Some more advice: Make this method extend \Phalcon\Mvc\User\Component. You will then have access to your configuration service via $this->config, rather than having to pass it to the constructor.

Thanks for your corrections! But the question is a little different.

.

Where should be the Plugin, and where should be the Component? And... Plugin or Component, eventually?

Because I'll use the createToken function, when I clicked the button on my login form. And also I'll use this function to identify the user, when its needed.

What is the best way to combine this? What is the best way to avoid repetition (Dont repeat Yourself)? For example, how should the Plugin or Component (or what) be looked?



125.7k
Accepted
answer

I've never used Plugins - Components work fine for everything I need. I think the differences are primarily semantic anyway.

I don't think you're in danger of repeating code anywhere. Maybe you would be if you wrote your own ACL component, but that's not necessary.

I would make this into a full fledged Component. You can then use it to listen for events - specifically dispatcher:beforeDispatch, and run the checkAccess() logic when that event is fired. This will result in the users access level automatically being checked on every page load - so you don't have to worry about manually checking.

I'd recommend looking through the INVO tutorial about securing the backend: https://docs.phalcon.io/en/3.3/tutorial-invo#securing-backend - there are lots of useful concepts such as event hooks and the ACL.