I have the table structure below
Here are the tables.
Users:
+ userid
+ roleid /* Associate a Role to a User */
Roles:
+ roleid
+ rolename
Permissions:
+ permissionid
+ permissionname
RolePermissions:
+ roleid
+ permissionid /* Associate a Permission to a Role */
Hoping the structure makes sense.
I need users with the change_password permission to be able to change a user's password. Which is simple just assign the permission to their role.
The complication is that certain roles can only change certain types of users' passwords. e.g A Janitor can change a Junior Janitors Password But not a Teacher's Password. So can't just do a $user->can('edit_password') check. Also don't want a bunch of if_this_role_is_editing_this_role checks. Is there a really nice way you guys would approach this? Thanks.
You can add a "power" col to your user table. That way, you can block an action if the user is doing an action on a user that has a power bigger or equal to his own power privileges.
Related
I have this simple MySQL table, which I called data_table:
/--------------+------------------+-------------------\
+ data_id + data_content + addition_content |
+--------------+------------------+-------------------+
+ data_1 + data_content_1 + comment_for_1 |
+ data_2 + data_content_2 + comment_for_2 |
+ data_3 + data_content_3 + comment_for_3 |
+ + + |
+ ... + ... + ... |
+ + + |
+ data_n + data_content_n + comment_for_n |
\--------+-----+------------------+-------------------/
To help users can submit their data to my database, I have created a simple HTML form (with PHP core) for easier data submission.
For getting data from this table (data_table), I have used this query (from my_query.php):
// ...
$var_get = $_GET['url'];
$query_1 = mysql_query("SELECT * FROM `MyDB` WHERE `data_id` = '{$var_get}'");
while ($query_2 = mysql_fetch_array($query_1))
{
echo $query_2['x_2'];
}
// ...
Anyone can see any result (from echo $query_2['x_2'];) when they access my_query.php page with a $_GET[]; value.
Now, I don't want to allow all people can access any data from my website. So, I decide to allow the access-permission to certain users only; and, I have an idea:
I will create a new MySQL table (user_table):
/--------------+------------------+-------------------\
+ user_id + user_name + user_password |
+--------------+------------------+-------------------+
+ user_1 + user_name_1 + password_1 |
+ user_2 + user_name_2 + password_2 |
+ user_3 + user_name_3 + password_3 |
+ + + |
+ ... + ... + ... |
+ + + |
+ user_n + user_name_n + password_n |
\--------+-----+------------------+-------------------/
Then, I will add a new data column (data_owner) to existed table (data_table). Every record (data line) will be have a owner; this owner is the existed user (in user_table) who submitted their data to my website.
Finally, I will add a new data column (allowed_user) to existed table (data_table). Every record (data line) will be have some allowed users; these allowed users are existed users (in user_table) who are allowed to see result (from echo $query_2['x_2'];). If someone is not an allowed user (from certain record), they won't see the real data.
My idea is not bad?
Sorry, programming is not my job; so, there are some limitations in my programming skills. Can you give me an example, please?
What you are describing is a basic login/auth system for users.
https://www.phpro.org/tutorials/Basic-Login-Authentication-with-PHP-and-MySQL.html
With this in place, users should only be allowed to update their own records.
If you would like admin users, or moderators, you could set up a simple Access Control List.
eg:
CREATE TABLE levels(
id int not null primary key auto_increment'
name varchar(20) not null
);
INSERT INTO levels(id, name) values (1,'admin');
INSERT INTO levels(id, name) values (2, 'moderator');
INSERT INTO levels(id, name) values (3, 'guest');
When a user logs in, you can check if they have moderator, or admin privileges to look at other user data.
There are also ACL implementations ready to go if you wish to use an existing solution.
Kev
You need to create one more field called role
for example: user_id,user_name,user_password,user_role
while register you need to pass role type as (admin,superadmin(optional),publisher,guest) you can add whatever you need in the role.
based on role you will need to give permission.
No, I don't think so! Your idea is not the best fix for the problem.
What you really need is an Access Control List just like Kevin Waterson said
I wouldnt advice you to implement your own ACL though. You could check out this ACL Library on GitHub, it's one of the best ACL Libraries for PHP out there, it doesnt have too much learning curve (if at all it has any) and it just works.
If you were to use the Samshal\Acl Library which I linked to above, the following snippet will help you protect your resources:
$permissionManager = new \Samshal\Acl(); #<-- Instantiate the ACL Class
#When you create a new data, add it to your ACL by doing
$permissionManager->addResource('data_1'); #<- data_1 is the id of your newly created data
#You need to also register users to the ACL
$permissionManager->addRole('user_n'); #<- user_n is the id (probably the username) of your just created user
#Then grant permissions by doing:
$permissionManager->user_n->can->view('data_1');
#Or deny permissions by doing
$permissionManager->user_n->cannot->view('data_1');
Save a serialized$permissionManager in a database or file and voila! You have successfully just protected every resource.
The library has other cool features too like allowing you to grant edit, create, delete or even allow you to create and attach an entirely custom permission like approveDataContent permissions on your resources.
You can visit https://github.com/Samshal/Acl/blob/master/README.md to learn more about the ACL library
I have a project that I am working on and I've been researching about having User Levels and the recommended & secure ways of doing it.
The project will have some more complex stuff like groups, users, pages, chat and I don't want to make some changes now and be required to re-change the logic when I will add the other features.
I would like some advice or help on this, I would appreciate it very much.
The way I was thinking was either
Have a table named userlevels (for example) with 3 columns ID, Name, Permissions
1, user
2, Administrator, {"admin": 1} with json
OR
Have an additional row with permissions in the normal users table, and have a row for example
is_admin [0,1]
Is it okay to do it like this ? If you have any other ideas for me I would honestly appreciate it very much.
Thanks in Advance!
I'll propose a more normalized solution that should be completely flexible going forward.
A table of users:
UserID (PK)
UserName
A table of permissions
PermissionId (PK)
Permission
A junction table to resolve the many-to-many relationship between users and permissions
UserID (FK to users)
PermissionId (FK to permissions)
I am new to php and I an currently creating a e-commerce site. I have created a CMS backend for the admin to add/edit/delete products, manage orders, manage shop configuration and add/edit/delete users.
I am having trouble finding out how to set user permissions/access rights so that:
- General staff only have access to managing orders and
- management staff have access to everything
So basically giving users a role which will give them restrictions or full access to everything.
Is there any tutorials or anyone with previous experience of adding this feature who can point me in the right direction?
Any help will be greatly appreciated. Thanks
An alternative design to what #Johnathan suggests would be a user HAS_MANY roles and each role HAS_MANY permissions.
Users:
+ id
+ name
Roles:
+ id
+ name
Permissions:
+ id
+ name
Then you link users to each of their roles, (and roles to each of their permissions), like this:
RolesUsers:
+ id
+ role_id /* Associate a Role to a User */
+ user_id /* Associate a User to a Role */
RolePermissions:
+ id
+ role_id /* Associate a Role to a Permission */
+ permission_id /* Associate a Permission to a Role */
Rather than cascading roles, or only allowing a user to be in a single role - users having multiple roles provides the most amount of flexibility.
Permissions are associated with Roles, and Users are associated with Roles. While there are, undoubtedly, many ways to implement this type of system, what follows is a quick concept from which you could begin thinking:
Users:
+ userid
+ roleid /* Associate a Role to a User */
Roles:
+ roleid
+ rolename
Permissions:
+ permissionid
+ permissionname
RolePermissions:
+ roleid
+ permissionid /* Associate a Permission to a Role */
Note in the first table how the role is associated directly from within the user table. You could break this out and put it in its own table if you wanted to assign multiple roles to a user.
Once this is all in place, or something similar to it, you can track the user's role via a session variable, and determine whether or not the user is permitted to perform any given action by looking up the id/name of that action, and the id/name of their role, in the RolePermissions table.
if ( $user->allowed( 'deleteUser' ) ) {
$users->remove( $uid );
}
Of course the database side is only the first part of the work. Next you would need to implement the connections between the database, and your code.
There are several ways of doing this that depends on how your app is going to grow. If you're pretty sure you'll only have these two profiles, then just add a "profile" field in your "user" table.
I suppose you have already implemented the login management, then you probably keep the logged user id in session. Just keep the profile type also and every time you display some component that should be accessible to the managers only, wrap it in
<?php if ($_SESSION['logged_user_profile'] == 'manager'): ?>
<!-- display your thing here -->
<?php endif; ?>
Note that this would only hide the elements. You would have to perform this check everywhere in your code also to prevent the corresponding actions from being executed...
A (much) better way if you use an MVC framework like CodeIgniter for instance would be to hook all requests through your access controller and redirect the user to a "access forbidden" page if he tries to access something he's not allowed to. This way, your access is controlled in one spot only.
Well, this is a complex subject that heavily depends on the architecture of your project so sorry if this doesn't answer your question correctly.
Extending from Jonathan's structure, I made a few modifications :
Users:
+ userid
+ roleid /* Associate a Role to a User */
Roles:
+ roleid
+ rolename
+ roleinherit /* Added this field */
Permissions:
+ permissionid
+ permissionname
RolePermissions:
+ roleid
+ permissionid /* Associate a Permission to a Role */
Being able to inherit from other roles can really help simplifying access control. For example, you could say that the "moderator" role inherits the "user" role which inherits the "guest" role. That way, you never have a guest that can do things even a moderator can't do.
Of course, this structure might be harder to implement as you can no longer create a simple query to check. A good way to handle these would be to create a recursive function that pulls data for the user's role, then merges it with the results of this function for the inherited role.
function getPermissions($roleID) {
// get info about this role and store it in $permissions. Assume we also set $inheritFrom
if ($inheritFrom == 0) return $permissions;
else return array_merge($permissions, getPermissions($inheritFrom));
}
Make sure to cache the results of this function, because it might become heavy.
I am building a web app which users use to assign tasks to each other.
The users are all on a LAN.
There is a basic permissions system already, where user roles are either Admin or normal user.
What I have to implement is something really fine-grained...and I cant think of a good way to do this
Heres a list of things I need to have control over:
If a user can change other users info
If the user can access the LAN network via VPN(this is another challenge all together, i think)
Users can assign tasks to only a set of other users(maybe all, maybe few)
If user has the ability to change/delete an already assigned task from another user
If the user can delete other users
If a user can change other users permissions
What I want is an example of something similar so that I dont have to re-invent the wheel. Or maybe an idea on how to implement this with as little headache as possible :P. Also I dont know how I would structure a MySQL table/s to store all these permissions.
I thought of assigning users roles but I need more flexibility than just those roles.
Any ideas?
One simple approach is to only have one extra column in the user table, called Access, Permission or something like that. Then for each of the permissions you want you define a constant with a integer value that's dividable by 2, or the number 1, e.g:
class PermissionChecker {
const CAN_CHANGE_OTHER_USERS_INFO = 1; // in bit form: 000001
const CAN_ACCESS_LAN_VIA_VPN = 2; // 000010
const CAN_ASSIGN_TASKS = 4; // 000100
const CAN_CHANGE_OTHER_USERS_TASKS = 8;// 001000
const CAN_DELETE_USERS = 16; // 010000
const CAN_CHANGE_USER_PERMISSIONS = 32;// 100000
public static function hasAccess($userAccess, $accessFlag) {
return $userAccess & $accessFlag; // The bitwise operation is the key....
}
}
$userAccess = 33; // read from database, in bit form: 100001
// check permissions like:
if (PermissionChecker::hasAccess($userAccess, PermissionChecker::CAN_CHANGE_OTHER_USERS_INFO)) {
// this will be true, because 100001 & 000001 returns 1
}
if (PermissionChecker::hasAccess($userAccess, PermissionChecker::CAN_CHANGE_USER_PERMISSIONS)) {
// this will be true as well, because 100001 & 100000 returns 1
}
if (PermissionChecker::hasAccess($userAccess, PermissionChecker::CAN_CHANGE_OTHER_USERS_TASKS)) {
// this will not happen... because 100001 & 001000 returns 0
}
Then when another permission level is needed you only have to add another number that's dividable by 2, e.g. 64, 128, etc. Maybe not the prettiest solution, but a simple one.
And when you want to store permissions for a user you use the bitwise-or operator, like:
$userAccess = PermissionChecker::CAN_CHANGE_OTHER_USERS_TASKS |
PermissionChecker::CAN_CHANGE_OTHER_USERS_INFO; // will give $userAccess = 9;
// then store $userAccess in the database for current user...
One option is to use a database table to store the permissions where a row is a single permission. If a permission is not present in the table for a given user_id then that user does not have the permission.
user_id | permission
-----------------------------
1 | CHANGE_USER_INFO
1 | DELETE_USERS
1 | CHANGE_USER_PERMISSIONS
2 | VPN_ACCESS
As you can see, user 1 would be able to change info, delete and change permissions. User 2 can only access the VPN. This would be easy to add and remove permissions, you'd just need to insert or delete. It would also be easy to create new permission types in future.
To address your point number 3. That one would be more complicated. For that you could have another table with columns user_id and target_user_id where you would insert the user_id of which users can assign tasks to. Alternatively you could add another column to the table above like a generic ID, then insert ASSIGN_TASK and populate the ID column with the target user.
Allow the administrator to define roles, as well as define which powers to give each role. That can be done with a bitwise comparison (good), or with a many-to-many relationship database tables (better).
This system gives you most flexibility, as it easily allows you to add new abilities without reconfiguring the whole system of roles.
I'm going to allow companies to register on my website and create job listings.
I'm currently approaching the problem by creating a Company table with Name, Logo and Password fields. Then when a person registers he can say, "I belong to X company"; at this point, I'll request the password written in by the initial registrator. If she/he enters the correct password then he is given permission to create job postings in the name of the company.
Why I'm doing things this way:
If I just put everything inside of the Company table, every new user would have to create an account and I'll have redundant information, CompanyName, Logo, etc.
And if I do things without a password, anyone can post a job opening under a companies name and that's just wrong.
Care to share some input? Am I doing things wrong? How would you do it?
I would do "jobs requests" like Facebook's friend requests and if the user really work in that company, the company manager just has to login and confirm it.
Database Normalization.
Create a separate Users and Companies table. Can one user post for multiple companies? if so, you need a many-to-many relationship (which requires a third table to keep track of the relationships). Otherwise, a one-to-many should work.
You should create two tables:
Company:
- id
- logo
( - name, etc )
User
- id
- companyId (foreign key to Company.id )
- password
( - username, etc. )
This way a User is a child of a Company identified by companyId. Now, if a user logs in, you can identify what company s/he belongs to by finding the Company corresponding with the companyId. Now you have a password per user, and a company per user.
And like Jimmy says, if you need Users to be able to be part of more Company's you would get:
Company
- id
- logo
User
- id
- password
Company_User
- companyId (foreign key to Company.id )
- userId (foreign key to User.id )
in my opinion you should create table like
Employers:
eid(pk)
logo
Username
Password
profile
etc....
JobSeekers:
jid(pk)
Username
Password
etc...
JobPosts:
id(pk)
eid(Fk to Employers.eid)
JobTitle
Specifications....