Using the Gateway interface for evaluation
In addition to the powerful features already listed here, the PropAuth
library also provides a simplified interface for working with your user (subject) and its authentication and authorization.
First, let's take a look at authentication. It uses a bcrypt
hashing method behind the scenes to evaluate the password:
<?php
$myUser = (object)[
'username' => 'ccornutt',
'password' => password_hash('test1234', PASSWORD_DEFAULT)
];
$gate = new Gateway($myUser);
$subject = $gate->authenticate($password);
// Then we can check if the user is authenticated
echo 'Is authenticated? '.var_export($subject->isAuthed(), true)."\n";
?>
We create the Gateway
class instance and then can call the authenticate
method on it with the password provided. The script then assumes it can access the user's password
property as a value on the object and makes a comparison. It will return a new instance of a Subject
class if the authentication is successful or false
if not. The Subject
class is just a wrapper around your object ($myUser
in this case). The original object can be fetched using the Subject->getSubject()
method.
Additionally, you can provide a bit more context and use the Gateway
interface for policy evaluation too. You simply define the policies as a part of the Context
object in the constructor:
<?php
$context = new Context([
'policies' => [
'policy1' => Policy::instance()->hasUsername('ccornutt')
]
]);
$gate = new Gateway($myUser, $context);
// When we can call the "evaluate" method with the policies we want to check:
if ($gate->evaluate('policy1') === true) {
echo 'Policy1 passes!';
}
// Or you can just add your own PolicySet instance and use "evaluate" the same way
$myPolicySet = new PolicySet()->add('edit-post', Policy::instance()->hasUsername('testuser1'));
$context = new Context([
'policies' => $myPolicySet
]);
?>
Once you have your valid Subject
instance, you can then check its abilities with the can
and cannot
methods:
<?php
$myUser = (object)[
'username' => 'ccornutt',
'password' => password_hash('test1234', PASSWORD_DEFAULT)
];
$context = new Context([
'policies' => [
'policy1' => Policy::instance()->hasUsername('ccornutt')
]
]);
$gate = new Gateway($myUser, $context);
$subject = $gate->authenticate($password);
if ($subject !== false && $subject->can('policy1') === true) {
echo 'They can, woo!';
}
?>
The parameter on the can
and cannot
methods are policy names you've already defined in your context. If the Policy
is defined as a closure with more complex logic, you can provide this option (or multiple options) as the second parameter:
<?php
$post = (object)[
'author' => 'ccornutt'
];
$set = PolicySet::instance()->add(
'delete',
Policy::instance()->can(function($subject, $post) {
return ($subject->username == 'ccornutt' && $post->author == 'ccornutt');
})
);
$context = new Context(['policies' => $set]);
$gate = new Gateway($myUser, $context);
$subject = $gate->authenticate('test1234');
if ($subject->can('delete', $post) === true) {
echo 'They can delete it!';
}
?>