user, role, permissions and a specific group RBAC? - mysql

I am trying to design a database schema for a project using mysql as the database. and i am stuck on the authorization part, the business rules are as follows:
a role can have many permissions, and a permission and can be inserted in many roles
a user can have many roles, and one role can be assigned to many users
now this is the part that can't get it right, Every user can be in many "groups" but in each he can be assigned only to one role (by groups i mean group of people and not group of roles)
the following picture is what i came up with till now, what should be amended?

Based on your question and answer to my comment, here is the model I came up with:
This meets your requirements. The main difference with your model is how the groups are setup.
Group has a 1:1 relation with Role, which can be null (i.e. a group can exist even it no role is associated to it).
In each Group, you have a foreign key to the Role table.
If you need to know the roles a users has: individual roles through User_has_Role + role attached to each group the user is a member of (through Group_has_User).

There can be a table for each group which contains user and effective role(as user in one group can have only one role). There is also one implementation specific flaw, if user can be in multiple groups and in one group he can have only one role, so there must be some provision to decide effective group for the user which is going to decide effective role for user.
If users relationship with the group is only factor that decides the role user can have, then there is no point of having direct relationship between user and role.

Related

MySQL user belongs to organization

I have a user table setup where a user can either belong to a Supplier or a Customer organization, which can have multiple users.
My original idea for the User table was to have a customerID and a SupplierID in the user table, out of which one will be filled, based on the organization the user belongs to. This does however not feel right, but I feel like maintaining two linking tables for this is overkill as well.
What would be the best practice in this case? I do not expect there to be any more organizations added in the future, but I do want to futureproof the application, by allowing multiple users to belong to the same organization.
you can design user or organization table with a column organization type which has value: supplier/customer and a column for organizationId

Database Tables for User management

I would like to get some advice from you about best practices in user role management.
I would like to create an application where user register and will have different roles. Now the obvious thing is, to create the users table and save the user data there like this:
users
id
userUUID
username
role
But I think about separated tables for different groups. So like:
admins
id
userUUID (-> foreign key users table)
accessRight1
accessRight2
subscribers
id
userUUID (-> foreign key users table)
etc
Does this make sense? So should all users, regardless of their role be in one database? And what is then about the specific information for different roles?
Thanks!
If your roles are rarely going to change that would probably work. But, you should always plan for change, and a more flexible option allowing you to add roles without needing to change your database schema would be something like this:
Users:
uid
user info...
Roles:
rid
name
UserRoles:
uid (FK to user table)
rid (FK to roles table)
In your code you could then check the UserRoles table to determine if the user has a given role and therefore should be allowed to do whatever.
Additionally, if you want to mix and match permissions for actions across multiple roles (i.e. both Admin's and Moderators have permission to delete posts or something). You could add another level with a Permissions table, and a join table (RolePermissions) linking that to the Roles table. You're access checks would become slightly more complicated then, requiring you to join the UserRoles table and RolePermissions join table to determine if a user has a given permission to do something.
Something like this:
SELECT *
FROM UserRoles u INNER JOIN RolePermissions p
ON u.rid=p.rid
WHERE u.ID=<USER> AND p.pid=<PERMISSION>

Best way to store a one-to-many column in database

I have a users table in my database and have three kinds of user roles - manager(admin), expert, and student.
I have tried storing their role as column role in the users table, but my question is what is the best way to store it?
For example, should I use numbers - 1 for admin, 2 for expert and 3 for student. Or only one character - 'A' for admin , 'E' for expert and 'S' for student? Or full string 'admin' for admin and so on, or what?
Edit
Guys, I want most efficient way. Some of you told me to have another table but this relationship isn't many to many, it's one to many because users can only have one role.
You might want to have a separate junction table, eg user_roles that will have columns: id, user_id and role_id. This way each user can have multiple roles in the future, even if right now they only have 1.
And that role_id would point to a role in a new roles table, which could have all the data associated with the roles.
Or if you really don't want the junction table, then just put the role_id directly into your users table.
Look up database "normalization". Basically if you have a specific set of data that will be repeating in a column, you might want to put it in its own table.
You could create a separate table showing 2 columns: role_nbr, role with values like:
1, Admin;
2, Expert;
3, Student
Then include role_nbr in your users table and use numbers, linking it to the role table to lookup the role name. That way, if you ever increase your roles, it's easy to add to the separate table. A good study would be on normalization - this will help you eliminate storing duplicate information where you have a lot of information to store (like the role name - since storing a number or letter - how would you remember what it stood for?)
Use the enum type. Here is an example
CREATE TABLE users (
-- the other columns
role ENUM('admin, 'expert', 'student')
);
An ENUM is a string object with a value chosen from a list of permitted values that are enumerated explicitly in the column specification at table creation time.
This means that the enum type has already defined values (and can contain only one value per row - you can't have a user who is admin and at the same time student). In your case, they are admin, expert and student.
DOCS

ASP MySQLRoleProvider tie roles to users

I would like to use the mysql role provider for aspnet. I have setup a custom table for the users using the attribute userTableName="user". Now the problem is that when I assign users to roles, MYSQLRolesprovider creates an entry in a table "my_aspnet_usersinroles" which and "my_aspnet_users". I would like to specify that the table used to specify roles should be the "user" table. How do I do that? Do I need to write a custom role provider? Is there a setting that I can tweak to make that association? Or am I just using this whole system wrong? Thanks
specify that the table used to specify roles should be the "user"
table.
If you want Membership Provider to use your User table, you need to implement Custom Membership Provider.
Custom Membership Provider requires a lot of work especially if you are new to Membership Provider and Provider Model.
Alternative Approach
Use FormAuthentication if you do not need Membership Provider's all features.
OR
create UserId in User tables as PrimaryKey as well as ForeignKey like the following. (One draw back in this approach is you can only use in new application; you cannot implement in existing database.)
You need separate tables for users and their roles. Generally, it's three in total, one for the users, one for the roles, and one to tie a user with one or more roles. The usersinroles table allows the one to many relationship so your user can have more than one role. Also, good database design would dictate this as well as the user table should only contain artifacts directly related to the user itself.

Many-to-One and One-to-One Relationships on Same Two Tables?

I'm designing a database where two fields have a many-to-one relationship, but I also need a one-to-one relationship between them, and I would like some advice on whether there is a better way to do it than what I've got right now.
My tables are accounts and users. An account can have multiple users, but each account can only and must have one owner. A user can be related to only one account.
I have an account field in the users table, which stores the ID of the account the user is related to. In the accounts table, I have an owner field, which stores the ID of the user who owns the account (i.e. the head admin).
I'm using InnoDB so I can make use of foreign keys. The problem is that I can't create an account or a user without the other being created first (due to the restraints of the foreign keys), so I made owner nullable. Now I can create an account with a null owner, then create the user, and finally set the owner on the account to the user.
Is this acceptable, and is there a better way?
Here are some possible other ways I've come up with, and my thoughts on each:
Have a boolean owner field in the users table. Since every account can only have one owner, this way seems less than ideal because I'd have to ensure only one user per account has the attribute set to true.
Have a third table called owners. This seems like more overhead and more work for no good reason since it's effectively the same as having an owner field in the users table.
How I have it now makes the most sense to me, but it's a little awkward having to set a null owner until I create the user, and then coming back to set it after the fact.
I'd appreciate any input you can give me. Thanks!
This question is similar, but there's no mention of foreign keys: Designing Tables: One to many and one to one at same time?
In general is a bad idea if your schema cannot be sorted topologically, i.e. if you cannot establish an ordering where a table only refers to tables preceding it in the ordering. This sort of "layered" dependency is also a very nice property to have for example for software modules (you have a problem if two modules depends on each other).
In your case you have user that refers to account and account that refers to user so clearly there's no way to find a topological ordering.
One standard solution in this case is to introduce a separate table e.g. "role" where you have three columns: user, account and role. The column role can be either "owner" or "guest".
The fact that you know that (given the current requests) an account must have one and only one owner, or that a user must be listed in one and only one account are not IMO rules that are really pertinent to the domain of "users" and "accounts".
You can implement those rules easily, but structuring your data so that you have no other possibility is IMO a mistake. You should aim to model the domain, not the specific rules... because people will change their mind about what those rules are.
Can you conceive a user with two accounts? Can you conceive an account with multiple owners/admins? I can... and this means that most probably quite soon this will be a request. Structuring the data so that you cannot represent this is looking for troubles.
Also when you have cyclical dependencies in the model your queries will be harder to write.
A very common case is for example to try to represent a hierarchical part list database using just one table with a "parent" field that points to the table itself... much better is having two tables instead, part and component, where component has two references to part and and a quantity.
Your solution is fine.
If you're uncomfortable with the owner column being nullable, you could rely on some magic user record (perhaps with an id of zero) which would be the "system user". So newly created accounts would be owned by user-zero, until their ownership was suitably redefined. That seems smellier than allowing accounts to have a null owner, to me, anyway.
For the current requirement to have only one account per user
alter table UserAccount add constraint un_user_account unique(UserID);
and when the requirement changes to many-to-many, drop the constraint
alter table UserAccount drop constraint un_user_account;
For the one owner only, simply enforce that on the application level.