I'm currently working on a platform which is planned to coordinate the communication with customers in future. Users can be added to projects and have certain rights. Therefore users are assigned to different user roles (admin/manager/member/viewer). Admins can view all projects and are allowed to add other users to a project. If a user (e.g. role:member) is added to a project, he will have certain rights (depending on the role), if not, he is not allowed to access the project at all.
I'm using Cake's ACL Component and everything is working great, when i disregard if a user is added to a project or not. The only solution I can think of, is not to grant rights on the group-level, but on the user-level when an admin adds an user to the project.
Is there an easier way to solve this issue? Otherwise I'm afraid that the code would become totally confusing.
There is a another way (I don't really know if easier, depends on your point of view). The ACL component only helps you to create roles, but you need a role and project-access management, right?
What I do in this cases:
Create a Project_Permission table in your database (give it a better name, I'm lacking imagination). Depending on your project, create the associations: a user can be related to many projects and a project can have many users accesing it. If you are following the cake conventions (and your tables are named users and projects) and it doesn't interfere with what you already have, the table should be
PROJECTS_USERS
id
project_id
user_id
created and modified //if you want to
Create appropriate actions where the admin (or other type if users, that's up to you)
can add users to projects and save that many-to-many association in
the previously created table.
Since the authorization for the project does not come from the ACL component, you have to create an "authorization" function yourself. I recommend putting this in the beforeFilter() function of the AppController (if you don't have an AppController, you'll have to do it in every controller you want this to work). In this function, check if the logged user is in the existing table and has an association with the project. Something like:
function beforeFilter() {
//let's assume you have the project id somewhere, in a global variable like $this->_projectID
$user = $this->Session->read('Auth.User.id');
$project = $this->Project->find('first', array('conditions'=>array('id'=>$this->_projectID, 'User.id'=>$user)
if (count($project) > 0) {
//the user has permission to see the project
} else {
//he doesn't
}
}
It's difficult to give an actual code because I'm not sure of your model associations nor where do you want the code or if you have the variables needed for this available everywhere, but I hope you get the idea. After that it's just a matter of how you want to handle the restriction of access (normally a flash message and redirection is involved).
I hope this is clear enough :S
Related
there are websites which create custom sessions for users, giving them unique link to the exact session user has created. E.g. it would like something like https/website.com/session/UniqueRandomID. I guess I understand how custom routes in ExpressJS work, but I'm not quite sure how can I allow a user to create those and later allow other users to connect only to those which have been already created..
Is there a common way of doing it and what may I be missing on the topic?
I tried searching the expressJS documentation.
The term "session" has a rather specific meaning in web site development (it refers to data associated with a given browser's visit to a site and is used for things like tracking the logged in state of a user) so I'll use the term "project" in this answer.
When the user creates a project, store all the information about that project in a database. Include, as part of this information an identifier. You probably want this to be a GUID or similar (there are libraries which will generates these for you) rather than something sequential (like an automatically generated database primary key).
The first page of the React Guide explains routing. Create a route that uses a route parameter for the project ID.
Use that project ID to get the data about the project from your database.
If there isn't any for that ID, return an error.
app.get('/projects/:projectId', async (req, res) => {
const projectData = await getProjectData(req.params.projectId);
if (projectData) {
return res.render('projectView', projectData);
}
res.sendStatus(404);
})
I made OnBeforeinitialize hook. I need place there code which register new user if user doesn't exists in database.
Which MediaWiki class and functions should be used?
If you need to create users, chances are you are doing something wrong. Users should be created on login/signup (use a PrimaryAuthenticationProvider to tell the system to create them), or when they are authenticated based on request data (use a SessionProvider). There is also User::newSystemUser but it's only meant for scripts.
Even if I don't know, what you really want to do, where the data for the user should came from, and why you want to do this in the BeforeInitialize hook (so, in fact, any useful information to really know and understand what you want to achieve is missing, therefore, you'll get an answer to your concrete question without any guarantee, that it works like you expected in your use case). However, to create a new user, you can use the createNew function of the User class. You should check, if the user is already present in the database.
EDIT:
An usage example:
$user = User::createNew( 'Testuser', [ 'email' => 'email_from#external_source.com' ] );
Following scenario:
I have a multi tenant web application in Yii2' advanced template.
This application has three portals:
- backend
- dashboard
- frontend
Each portal has its own user table for authentication.
(-frontend_user,
-dashboard_user,
-backend_user)
Frontend and dashboard can reached with the tenant's name at the end, e.g.:
When a user tries to login to dashboard or frontend I have to check if they have a right to login.
This happen via contingency table (e.g.: dashboard_user_tenant)
Now I want to build a rbac for the dashboard application.
But roles should not hang at the dashboard user but at dashboard_user_tenant (the contingency table),
because rights can change in each tenant's dashboard.
Yii2 has its own rbac system, but as I understand so far, it doesn't fit on my needs.
Any chances to customize Yii2's rbac or is it better to build my own custom solution? Maybe my own component?
I hope my description is clear enough :)
I had a similar desire in one of my projects, but I didn't create my own full RBAC system, instead I overwrote a way of checking for the roles
In my User component class, I extend the \yii\web\User, and also overwrite the can() function of that class. That lets me use my own way of checking for the appropriate permissions. For example
<?php
namespace app\modules\users\models;
use Yii;
use yii\web\User as WebUser;
use app\modules\users\models\UserPermissionManager;
class User extends WebUser
{
public function can( $operation, $params = [], $allowCaching = true )
{
if(Yii::$app->user->isGuest)
{
return false;
}
return ( new UserPermissionManager() )->has( $operation );
}
}
In the UserPermissionManager class, it queries a database table that is full of permissions such as "users:access", "users:edit", etc
They all have a certain user level assigned to them which relates to the user level I have set in my Users database table.
All the can() function needs to do is return true or false, depending on if this user has the permission to do what it's being asked. You can handle this however you like really.
It's quite a big system to explain fully in one post but I hope it's helped slightly, feel free to let me know if I can explain anything any better!
I have a custom permission model for my project and I'm not using django's default permissions backend. I have a custom has_permission template tag to check if the user has the specified permission or not.
The problem is that there's lots of queries done for the same checks every time, I'm looking for a way to reduce my Permission queries. What I'm doing inside my templates is like :
{% if user|has_permission:'jpermission.can_edit_jpermission' or
user|has_permission:'jgroup.can_edit_jgroup' or
user|has_permission:'role.can_edit_role' %}
and the code for has_permission template tag is as follows :
rep = perm_name.split('.') # rep is for e.g. "jpermission.can_edit_jpermission"
ctn_type = rep[0]
codename = rep[1]
pr = JPermission.objects.filter(model_name=ctn_type, codename=codename)
if pr.exists():
if user.has_perm(pr[0]):
return True
Specifically talking, the problem is that every time i check even for the exactly same if statements, lots of queries are made (from what I'm doing, it's obvious there will be).
Is there any other way i can go at it ? like query all permissions once, cache them, and do something like how prefetch_related is handled to prohibit further db queries (python filtering with loops and ... ) ?
P.S: has_perm is also overridden and checks if users role, group or permissions have the specified permission or not)
There are multiple solutions for this.
Move permissions to user model as methods of model and use cached_property decorator so that consecutive calls to methods does not hit database again.
Store the permissions state in session when user logged in, and later use session data to check for permissions.
It looks like you are using django-guardian, and it is already caching the permissions:
Once checked for single object, permissions are stored and we don’t
hit database again if another check is called for this object. This is
great for templates, views or other request based checks (assuming we
don’t have hundreds of permissions on a single object as we fetch all
permissions for checked object).
I'm really struggling to wrap my head around some of this stuff. Let me give an example of where I'm struggling.
I'm using Linq-2-Sql as the DAL for my app and the IRepository pattern used in the MVC Storefront sample app from Rob Conery.
In my domain I have a Customer Model which has a collection of Address Models. In my UI there is a button which allows the user to add a new address to the customer. This opens up an address editor which let's them fill in all the information.
What happens next? Does the address get saved to the database, then added to the list in my customer object? Does it just get added to the list but not updated until the Customer object get's saved? What if the user wants to delete an address? Do I delete the address in the database and then remove it from the list? Or do they just make all the deletes/adds they want and I dump everything from the database everytime and update it with whatever is in the Customer.Addresses collection? What's the right flow here?
Should the collection of addresses only get updated via the Repository by calling something like this:
public void AddAddressToCustomer(Customer c, Address a)
{
//validate and save address to db
//add the newly saved address to the Customer Object
}
Help...
DDD is an area where I have a lot of interest but but very little experience so please treat my suggestions cautiously. I only offer them because of the absence of other, more authoritative, answers.
In 'the book' by Eric Evans address is given as an example of something that should typically be treated as a Value Object rather than as an Entity. So I believe the Add method would belong to the Customer:
customer.Add(address);
There would be a Customer Repository (but not one for addresses). This might be used like this:
customerRepository.Update(customer);
The intentional affect of this is that all the difficult questions you ask about how this is then implemented at the DB layer are not the concern of the domain objects (i.e. the customer object). I'm afraid I can't help beyond that point either.
Sounds like you don't know the context of your domain as well as you need to. Ask some more questions and get a better user story. Potentially any of your proposed scenarios may meet the business need, depending on what it is. When you understand the need then I believe this issue will iron itself out.
it depends had a great start on the answer. Once you add the address to the customer and save the customer using:
customer.Add(address);
customerRepository.Update(customer);
Your repository would then map your customer and address domain layer entities to LINQ to SQL. This will likely involve creating a new DataContext object, getting the related LINQ to SQL entities (or creating new ones) and then mapping the domain layer entities to your LINQ to SQL entities.
var context = new MyDataContext();
var linqCustomer = MapCustomerToLinqCustomer(context, customer);
var linqAddress = MapAddressToLinqAddress(context, customer.Addresses.First());
context.SubmitChanges();
You could also use DataMapper classes for mapping, but the MapXYZ methods more closely follow Rob Conery's example. If you need more help with the MapXYZ methods, let me know.