How to access $user in custom Authorization
- kevin.waterson@gmail.com
- Member | 81
How can I access $user inside my Authorization class?
This is what I currently have, but when I try to access $this->getUser(),
I get an error:
Call to undefined method App\Model\DrpAuthorization::getUser()
This is my class:
<?php
declare(strict_types=1);
namespace App\Model;
use \Nette\Security\User;
class DrpAuthorization implements \Nette\Security\IAuthorizator
{
protected $db;
public function __construct(\Nette\Database\Connection $db )
{
$this->db = $db;
}
public function isAllowed($role, $resource, $privilege): bool{
$user = $this->getUser();
$sql = "SELECT g.name AS role, r.name AS resource, e.name AS entitlement
FROM groups g
JOIN policy p ON g.id=p.group_id
JOIN resources r ON r.id=p.resource_id
JOIN entitlements e ON e.id=p.entitlement_id
JOIN user_group ug ON ug.group_id=g.id
JOIN users u ON u.id=ug.user_id
WHERE u.id=2";
$roles = $this->db->query( $sql );
$acl = new \Nette\Security\Permission;
foreach( $roles as $r )
{
if( !in_array( $r->role, $acl->getRoles() ) )
{
$acl->addRole( $r->role );
$acl->addResource( $r->resource );
$acl->allow( $r->role, $r->resource, $r->entitlement);
}
}
return true;
}
}
?>
- kevin.waterson@gmail.com
- Member | 81
MajklNajt wrote:
You do not need user in authorizator, you must authorize the role
So, once the roles, resources, and privileges are set, is there a function to check if a role has privilege on a resource..
In my Authorizator, what function needs to be called to determine if the role is authorized?
- n3t
- Member | 37
In authorizator method isAllowed
have to return
true/false
if given role is authorized to resource –
privilege.
You should propably load your definition in constructor, not in
isAllowed
method.
In presenter you can check right for example like this
$this->getUser()->isAllowed($resource, $privilege)
- kevin.waterson@gmail.com
- Member | 81
CZechBoY wrote:
You implement that authorizer so you should implement the method.
But easier is to create permission factory which just fills (and returns) Nette\Security\Permission.
A permission factory with Authorizator, or instead of Authorizator?
- CZechBoY
- Member | 3608
When I take your previous code I would end up with something like this.
I didn't test it, I didn't lint it, maybe there is bug/compile error –
I just want to show you what you should write instead of reinventing
authorizator.
declare(strict_types=1);
namespace App\Model;
use Nette\Security\IAuthorizator;
use Nette\Security\Permission;
class DrpAuthorizationFactory
{
protected $db;
public function __construct(\Nette\Database\Connection $db)
{
$this->db = $db;
}
public function createAuthorizator(): IAuthorizator
{
$sql = "SELECT g.name AS role, r.name AS resource, e.name AS entitlement
FROM groups g
JOIN policy p ON g.id=p.group_id
JOIN resources r ON r.id=p.resource_id
JOIN entitlements e ON e.id=p.entitlement_id
JOIN user_group ug ON ug.group_id=g.id
JOIN users u ON u.id=ug.user_id";
$roles = $this->db->query($sql);
$acl = new Permission();
foreach($roles as $r)
{
if(!in_array($r->role, $acl->getRoles(), true))
{
$acl->addRole($r->role);
}
if ( !in_array($r->resource, $acl->getResources(), true))
{
$acl->addResource($r->resource);
}
$acl->allow($r->role, $r->resource, $r->entitlement);
}
return $acl;
}
}
and config
services:
authorizatorFactory: AuthorizatorFactory
authorizator: @authorizatorFactory::createAuthorizator()
- kevin.waterson@gmail.com
- Member | 81
CZechBoY wrote:
When I take your previous code I would end up with something like this.
I didn't test it, I didn't lint it, maybe there is bug/compile error – I just want to show you what you should write instead of reinventing authorizator.
Thanks for the direction. With a little tweaking, it looks like this:
<?php
declare(strict_types=1);
namespace App\Model;
use Nette\Security\IAuthorizator;
use Nette\Security\Permission;
class DrpAuthorizationFactory
{
protected $db;
public function __construct(\Nette\Database\Connection $db)
{
$this->db = $db;
}
public function createAuthorizator(): IAuthorizator
{
$sql = "SELECT g.name AS role, r.name AS resource, e.name AS entitlement
FROM groups g
JOIN policy p ON g.id=p.group_id
JOIN resources r ON r.id=p.resource_id
JOIN entitlements e ON e.id=p.entitlement_id
JOIN user_group ug ON ug.group_id=g.id
JOIN users u ON u.id=ug.user_id";
$roles = $this->db->query($sql);
$acl = new Permission();
foreach($roles as $r)
{
if(!in_array($r->role, $acl->getRoles(), true))
{
$acl->addRole($r->role);
}
if ( !in_array($r->resource, $acl->getResources(), true))
{
$acl->addResource($r->resource);
}
$acl->allow($r->role, $r->resource, $r->entitlement);
}
return $acl;
}
}
?>
And the config:
services:
authorizatorFactory: App\Model\DrpAuthorizationFactory
authorizator: @authorizatorFactory::createAuthorizator()
Then, in the presenter startup() function:
<?php
protected function startup(): void
{
parent::startup();
if (!$this->getUser()->isAllowed('admin')) {
throw new Nette\Application\ForbiddenRequestException;
}
}
?>
I think I am doing something wrong in calling $this->getUser()->isAllowed() function, because I get an error:
Nette\InvalidStateException
Role 'authenticated' does not exist
Which seems to be the state of the login, rather than a Authorizator
thing.
What should I be calling here, to check if Authorizator is true/false?
- kevin.waterson@gmail.com
- Member | 81
CZechBoY wrote:
send how do doing authentication, especialy part with
new Identity(userid, roles, identity);
<?php
namespace App\Model;
use \Nette\Security\IIdentity;
use \Nette\Security\Passwords;
use \Nette\Security\IAuthenticator;
use \Nette\Database\ResultSet;
class DrpAuthenticator implements IAuthenticator
{
private $context;
private $passwords;
public function __construct(\Nette\Database\Context $context, \Nette\Security\Passwords $passwords)
{
$this->context = $context;
$this->passwords = $passwords;
}
public function authenticate(array $credentials): \Nette\Security\IIdentity
{
[$username, $password] = $credentials;
$row = $this->context->table('users')
->where('username', $username)->fetch();
if (!$row) {
throw new Nette\Security\AuthenticationException('User not found.');
}
if (!$this->passwords->verify($password, $row->password)) {
throw new Nette\Security\AuthenticationException('Invalid password.');
}
$roles = [];
$res = $this->context->query( 'SELECT g.name FROM groups g JOIN user_group ug ON g.id=ug.group_id JOIN users u ON ug.user_id=u.id' );
foreach( $res as $r )
{
if( !in_array( $r->name, $roles ) )
{
$role[] = $r->name;
}
}
return new \Nette\Security\Identity($row->id, $roles, ['username' => $row->username]);
}
}
?>
- kevin.waterson@gmail.com
- Member | 81
n3t wrote:
Role
autheticated
is default user role, that is used automatically, when user does not have any role. Check if your user is assigned to some role, or try to logout / login, as identity is kept in session.
OK, a bit embarrassing, but
$role[] = $r->name;
should be
$roles[] = $r->name;