Set user permissions on each module in Yii2 - yii2

I would like to set user permissions on each module.
Each module would have its table with the permissions. What is the most recommended way to do this?
Reason: My application has some optional modules for only a few clients.
UPDATE
Something like:
Table: mod_inventory_permission
id int
User_id int
Read_permission boolean
Write_permission boolean
Admin_permission boolean

You can use RBAC for it! you can set different modules in it and different permission for each module.

Yes you can do it by using Rbac which facilitate you to restrict user in same application to limited modules,controllers, or actions
You have to follow the following step i hope it will help you.
I suggest you to use the auth_ tables provided by yii2 for rbac
step 1: import all auth tables
step 2: Create different roles in auth_item tables with type = 1 and all permission with type = 2
Note
Please make sure you enter your permission in some specific pattern,i am using module/controller/action,
its up to you how you are going to implement it.
step 3: Create generic controller and extend all of your controller from this generic controller,
In your generic controller you have to check whether the user is allow to access the module,controller or action he/she want to access of not.
public function beforeAction($action) {
$module = Yii::$app->controller->module->id;
$controller = ucfirst(Yii::$app->controller->id);
$action = Yii::$app->controller->action->id;
if (Yii::$app->user->can($module)) {
if (Yii::$app->user->can($module . '/' . $controller)) {
return true;
}
if (Yii::$app->user->can($module . '/' . $controller . '/' . $action)) {
return true;
}
else {
throw new \yii\web\HttpException(403, 'You are not allowed to view this page');
}
} else {
throw new \yii\web\HttpException(403, 'You are not allowed to view this page');
}
}
The beforeAction function implement 3 layer authentication you can change it according to your requirements....
i hope it will help you

Related

Trying to update a column in database but NOT NULL attributes are not letting me update the values. I am using Laravel

I am trying to update the column with some other data but database table is not letting me update the table because of the NOT NULL constraints in it. I have this option of setting all the fields to NULL but I dont think that will be a good practice. Please I need a solution to it if anyone can help. I get the following error
Illuminate \ Database \ QueryException (HY000)
SQLSTATE[HY000]: General error: 1364 Field 'first_name' doesn't have a default value (SQL: insert into users (subject_id, updated_at, created_at) values (?, 2019-07-30 13:46:42, 2019-07-30 13:46:42))
Previous exceptions
SQLSTATE[HY000]: General error: 1364 Field 'first_name' doesn't have a default value (HY000)`
I have tried setting all the values to NULL and it worked but I want to work with some fields setting as NOT NULL and update the ones which are NULL and also if we can fetch or set the fields automatically to what we have ?
This is my controller where I am trying to update the field if this is required or help you understand my problem
public function deleteSubject($id) {
echo $id;
// die();
if(Auth::check()) {
$findSubject = Auth::user()->where('subject_id', $id);
$users = new User();
$users->subject_id = null;
$users->save();
// echo($findSubject);
// die();
Session::flash("message", "You subject has been deleted. You can add a new Subject now.");
return redirect('/subjects');
} else {
Session::flash("message", "Please sign in to access this page");
return redirect('/signup');
}
}
The following should work for your code. As it was said in the previous comment, it's because you try to create a new instance of a user without inserting value.
It look like you are trying to delete the subject associate with the authenticated user, so I suppose that you don't really need to create a new user, instead I think you should dissociate the user and the subject. So, the following should work for your code.
The purpose of that variant is to take the authenticated user and put a null value for the subject_id.
public function deleteSubject($id) {
echo $id;
// die();
if(Auth::check()) {
$user = User::where('subject_id', $id)->first(); // This will get the user that have the subect_id, but it's assuming that only one user have this subject_id.
// You can also do this just uncomment the first line below and comment the other one above.
// $user = User::find(Auth::user->id);
$user->subject_id = null;
$user->save()
Session::flash("message", "You subject has been deleted. You can add a new Subject now.");
return redirect('/subjects');
} else {
Session::flash("message", "Please sign in to access this page");
return redirect('/signup');
}
}
I think that you should take a look about how MVC work.
https://selftaughtcoders.com/from-idea-to-launch/lesson-17/laravel-5-mvc-application-in-10-minutes/
You should also take a look at relationship in Laravel: https://laravel.com/docs/5.8/eloquent-relationships
MVC and Eloquent-Relationships will help you understand some function in laravel to achieve this kind of goal really quickly.
If you get a User model and a Subject model, you can simply do something like this:
$user = User->find(Auth::user()->id);
$user->subjects()->dissociate($id);
I'm not sure, but I think the Auth facade let you use the user model function, so maybe this could work to:
Auth::user()->subjects()->dissociate($id);
You should also take a look at middleware: https://laravel.com/docs/5.8/middleware
With middleware, you can put rules like the one you are using to send a message to the user saying that he/she need to be log in to access the page into the middleware and reusing it whenever you need.

Symfony 3.4 : how to log the history of user actions?

I want to store in my database all the user actions done about an entity.
For example, for 1 entity, I want to store :
Created by (= author)
Updated by
Date of creation
Date of update
I want to store the history of the actions of a user, not the last ones. I thought I could create a table with these columns :
log_id
user_id
entity_id
action (= "create" or "update" or something else)
date
And then, I could easily get the last update of my entity and display the date and the user who did it.
Is there a Symfony bundle to do this ? Should I use Monolog ?
I will do this for many entities and I'm not sure if this is the correct way to do...
Is it possible to create only one logs table to store each log about each entity ? It bothers me to create 1 logs table per entity.
Since Doctrine is event based, it's easy:
Either use an extension, like Gedmo Loggable
Or hook into Doctrine's events and log, using Monolog, everything that happens in your app.
Personally I would prefer option 2 since I'm a control maniac, it's a little more complex though. Personally I would also use Monolog so I could abstract away the way how and where the log entries are stored.
When you decide how to approach this and you will need any assistance along the way, please ask another question.
Good luck.
I don't know if that would fit what you need, but you could easily add a Listener to the symfony kernel to log every controller used.
Something like this :
class UserLogListener {
protected $authChecker;
protected $tokenStorage;
protected $entityManager;
public function __construct(TokenStorageInterface $tokenStorage, AuthorizationChecker $authChecker, EntityManager $entityManager)
{
$this->authChecker = $authChecker;
$this->tokenStorage = $tokenStorage;
$this->entityManager = $entityManager;
}
public function onKernelRequest(GetResponseEvent $event)
{
if( $this->tokenStorage->getToken() != null){
$user = $this->tokenStorage->getToken()->getUser();
$currentDate = new \Datetime();
$action = $event->getRequest()->attributes->get('_controller');
$method = $event->getRequest()->getMethod();
$userIp = $event->getRequest()->getClientIp();
$userLogRepository = $this->entityManager->getRepository(UserLog::class);
if($user instanceof User){
$userLog = new UserLog();
$userLog->setUser($user);
$userLog->setIp($userIp);
$userLog->setAction($action);
$userLog->setMethode($method);
$userLog->setDate($currentDate);
if($event->getRequest()->request && $methode=='POST'){
$userLog->setData(json_encode($event->getRequest()->request->all()));
}else{
$userLog->setData($event->getRequest()->getPathInfo());
}
$this->entityManager->persist($userLog);
$this->entityManager->flush();
}
}
}
}
What it does is add to the database (with an entity called UserLog) information about every page called. So you can know which action is made by knowing which controller is called, and you can also log the request data so you can find out what modification/creation the user did.

How to conditionally use different database in CodeIgniter

Here is my scenario.
A user will login to the system. Based on the username, I need to set the database in codeigniter configuration.
I know that the line $this->load->database() in each model loads the default database.
So, after checking the username in session(assuming that the user has successfully logged in), how can I dynamically load a database?
Below is something that I am looking for:
if(username == 'foo'){
$this->load->database('database_name');
}
An example of a model function that I have written is as follows:
public function check_valid_login($username, $password){
$this->db->from('tbl_user_details');
$this->db->where('email_address', $username);
$this->db->where('password', md5($password));
$query = $this->db->get();
$rowcount = $query->num_rows();
return $rowcount ;
}
On selecting the database, how can I still use statements like $this->db->from('tbl_user_details'); and so on. i.e., I want to use $this->db itself. Is it possible to do that?
I think I found a solution.
This is the strategy that I followed: When the user tries to login, a session variable $_SESSION['dynamic_db_username'] is set with the username that is provided by the user.
The following logic is used for selecting the database dynamically. The below code is written in config/database.php
/*Dynamic database selection - begins*/
if(!empty($_SESSION['dynamic_db_username'])){
$dynamic_db_username = $_SESSION['dynamic_db_username'];
if($dynamic_db_username == 'sample#domain.com')
{
$db['default']['database'] = 'database_1';
}
elseif($dynamic_db_username == 'sample2#domain.com')
{
$db['default']['database'] = 'database_2';
}
else
{
$db['default']['database'] = 'database_1';
}
}
else
{
$db['default']['database'] = 'database_1';
}
/*End*/
Kindly review this strategy and please let me know if this is right.
in the config folder there was a file named autoload.php
open the file
find first this code below
$autoload['libraries'] = array('');
you have to put "database" in the array , changed code will be like
$autoload['libraries'] = array('database');
after that you can use your database anytime and anywhere without loading it manually .

yii2 RBAC for basic template role for group of users

I just want to know how can I assign roles to a group of users in yii2 using DbManager because I have seen a lot of tutorials but most of them are oriented to advance template and I'm using the basic template.
they mention folders like common, backend, that I donĀ“t find in basic template
Can you give me a tutorial or some guidance that I can follow?
thanks
Take a look at this page: http://www.yiiframework.com/doc-2.0/guide-security-authorization.html
That will help you add the DbManager for the RBAC. First you will want to create different roles and then you will need to add the permissions for the different roles.
Then when you create a user you will need to assign that user a role and they will have those permissions.
Here is a snippet from the docs for creating the roles and permissions.
<?php
namespace app\commands;
use Yii;
use yii\console\Controller;
class RbacController extends Controller
{
public function actionInit()
{
$auth = Yii::$app->authManager;
// add "createPost" permission
$createPost = $auth->createPermission('createPost');
$createPost->description = 'Create a post';
$auth->add($createPost);
// add "updatePost" permission
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'Update post';
$auth->add($updatePost);
// add "author" role and give this role the "createPost" permission
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
// add "admin" role and give this role the "updatePost" permission
// as well as the permissions of the "author" role
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// Assign roles to users. 1 and 2 are IDs returned by IdentityInterface::getId()
// usually implemented in your User model.
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
}
This RbacController.php file would go inside the commands folder in the base of your project. You can run it via the terminal by calling php yii rbac/init.
Then you will actually need to check if a user has certain permissions. So when an authenticated user is performing an action you can call something like
if (\Yii::$app->user->can('createPost')) {
// create post
}
where the string bassed to the can method is the permission that you are wanting to check.

Track data changes on tables using doctrine

So the situation is that I am using Doctrine as the ORM for one of my projects.
Now I want to be able to track the changes happening on certain tables of my website without having to much extra coding for that.
For eg. I have a database which has many tables. out of that i have a table users on which I want to track the changes done
1. users has column name with value 'Raman'
2. Using update sql below i modify the row
update users set name = 'Raman Joshi' where name='Raman'
Is there any in built feature in doctrine that allows to create a log table tracking all the data level changes log that was done?
You can use a Doctrine preUpdate event listener to do this. Here's a simple example that will send changes to a logger:
use Psr\Log\LoggerInterface as Logger;
use Doctrine\ORM\Event\PreUpdateEventArgs;
class ChangeLoggerListener
{
protected $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function preUpdate(PreUpdateEventArgs $eventArgs)
{
//find out class and id of object being updated
$obj=$eventArgs->getEntity();
$class=get_class($eventArgs->getEntity());
$id=$obj->getId();
$log="$class($id) updated: ";
//find out what has changed...
$changes=$eventArgs->getEntityChangeSet();
$separator='';
foreach ($changes as $field => $values) {
$log.=$separator."$field changed from {$values[0]} to {$values[1]}";
$separator=", ";
}
//send it to logger
$this->logger->info($log);
}
}
The manual page shows how to register the listener, but if you're using Symfony, you can register the listener as a service with this in your services.yml
my.change_logger:
class: My\ExampleBundle\Listener\ChangeLoggerListener
arguments: [#logger]
tags:
- { name: doctrine.event_listener, event: preUpdate }