Closed evgen-d closed 9 years ago
Another use case for calling checkAccess()
multiple times is building a navigation where most of the links need permission check to ensure user is allowed to access the corresponding action.
Current implementation I have results in about 100 db queries to build the navigation.
Some ideas here:
DbManager::cache
to indicate the cache ID being used. If not set, it means no caching.auth_item
, auth_rule
and auth_item_child
data. All these data are cached as a single entry in cache. Note that auth_assignment
is too big to be cached (imagine a system with millions of users). DbManager
is called to modify the auth data (e.g. add a new role, update a permission), it should invalidate the cache. It should also store the update timestamp in the cache.DbManager
is used to query auth data (e.g. checkAccess, get permission list), it should try to fetch data from three places:
Looks good to me. Assignment may be stored in web\User as a private property to ensure it only gets loaded once per request.
Another solution is to build a NoSQL-backed RBAC manager.
This extension caches checkAccess
result. This is not solution of multiple querying in checkAccessRecursive
. And when result is cached rbac may no longer be actual.
My proposal for cached rbac dbmanager https://github.com/mdmsoft/yii2-admin/blob/master/components/DbManager.php Each table load only once per request (except assigment when applied to more than one user). After loaded, data saved to memory. Then all process using data from memory. To save memory. Children and assigment, only saved as the name.
$this->_children = [
'parent_name1' => ['child1', 'child2', 'child3', ...],
'parent_name2' => ['child1', 'child2', 'child3', ...],
];
$this->_assigments = [
'userId1' => ['role1', 'role2', 'role3', ...],
];
Usiing rbac, i notice same problem that cebe wrote.... A large number of db query that solwly the app. So for now i rewrote some code to use with an other db. But the best solution for me is use cache components with a nosql db. (Redis or mongo)
@cebe wrote:
Another use case for calling checkAccess() multiple times is building a navigation where most of the links need permission check to ensure user is allowed to access the corresponding action. Current implementation I have results in about 100 db queries to build the navigation.
What about this case? Why not to cache assignments in memory to avoid duplicated queries in one request? I understand, why we can't use cache engine for this by default, but saving results of SELECT * FROM auth_assignment WHERE user_id='...'
in instance is must have: now Yii2 generates this query N times for N Yii::$app->user->can()
calls on the page (when building navigation, for example).
Caching auth items and etc. Discussion - #3166