45

I'm creating a website in which there are projects, users, and permissions for each user or groups of users. What this is is a community collaboration tool, and I have 4 different permissions:

  • Creator - make changes, accept changes, change permissions
  • Accept changes
  • Make changes
  • View

How could I implement, in a database, this kind of permission system, for groups of users?

Edit: Groups/permissions are defined by reputation, like on StackOverflow.

Edit 2 - more in detail: Each file needs to have a permission, projects need default permissions for newly created files, and I also need to set up MySQL database permissions.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • 2
    Do you have to use php? I know Django has great permission support out of the box. I'm guessing any given MVC (or similar) framework out there probably gives you similar permissions ease as well. Django is also really easy to get started on and learn. – wilbbe01 May 14 '11 at 22:44
  • @wilbee01 If he is doing website development then Django would not work since that is Python and he needs either PHP or ASP.net for web development. – Flipper May 14 '11 at 22:46
  • No, I can't, unfortunately :( – Ry- May 14 '11 at 22:47
  • You might find this thread interesting: http://stackoverflow.com/questions/5875646/database-schema-for-acl/5950425 – Denis de Bernardy May 19 '11 at 02:38

3 Answers3

60
user_table
id, etc

permission table
id, user_id, permission_type

with this structure, each user could have several permission types associated with their account, one for each set of features they could have access to. you would never need to change the table structure in order to add new types of permissions.

to take this a step further, you could make each type of permission a binary number. this way you could make a set of permissions be represented by one integer by using bitwise operators.

for instance if you had the constants

PERMISSION_CHANGE_PERMISSIONS = bindec('001') = 1
PERMISSION_MAKE_CHANGES = bindec('010') = 2
PERMISSION_ACCEPT_CHANGES = bindec('100') = 4

you could combine these values into one integer using a bitwise operator "|"

(PERMISSION_CHANGE_PERMISSIONS | PERMISSION_MAKE_CHANGES) = bindec('011') = 3 = $users_combined_permissions

then to check if they have a specific permission, use the bitwise operator "&"

($users_combined_permissions & PERMISSION_MAKE_CHANGES) = true

if you did that, you would only need one db record for each set of permissions.

dqhendricks
  • 19,030
  • 11
  • 50
  • 83
  • That is an interesting way of doing it, but i think that method would only be suitable for a system that would need to be complex and have a lot of different permissions. – Flipper May 15 '11 at 00:06
  • 13
    @Flipper I guess. It never hurts to think about the future however. Making your code agile can save a lot of time and headache at a later date. – dqhendricks May 15 '11 at 00:09
  • This is going to be a pretty complex system eventually, so it might come in handy - thanks! – Ry- May 15 '11 at 00:15
  • 6
    I finally ended up going with this. Thanks everybody. – Ry- May 24 '11 at 01:28
  • 1
    @dqhendricks, I like this idea for my system; but I have a question, what if I have multiple section system. For example, I want to grant user "XYZ" to have only `PERMISSION_CHANGE_PERMISSIONS` to the "news" section, and I also want to grant "XYZ" `PERMISSION_MAKE_CHANGES`, `PERMISSION_CHANGE_PERMISSIONS`, and `PERMISSION_ACCEPT_CHANGES` to the blog section? How can I differentiate the section? my first thought will be add a new column in the permission table with the section name but I am wondering if there is a better approach to this neat idea? – Jaylen Dec 02 '14 at 18:51
  • 1
    @Mike Well you could just use a naming convention and keep it all in the same column, like NEWS_PERMISSION_CHANGE_PERMISSIONS and BLOG_PERMISSION_CHANGE_PERMISSIONS. Two columns is equally viable. – dqhendricks Dec 04 '14 at 18:59
3

I have used Zend_Acl in the past for this. I can recommend it. A tried and tested library that is quite easy to implement and can be used stand-alone. This option will scale well if you have different permission schemes to add afterwards.

Stephane Gosselin
  • 9,030
  • 5
  • 42
  • 65
0

I would create two tables; users and ranks.

User
-----
id
username
rankID


Ranks
------
id
makeChanges
acceptChanges
changePermissions
view

Then just create the various ranks that you want in the Ranks table and set the rankID of the users to match the corresponding one that you want. Make sure to set in the Ranks table each field to a value of 0 or 1; with 0 being not having that ability and 1 having that option.

Edit If you were going to do this without a database then you could give do it with the classes or even instances in PHP5. For instance, let's say that you had set a name for each of the things that you had in your original post:

Creator - make changes, accept changes, change permissions
Reviewer - Accept changes
Editor - Make changes
Regular - View

Then you could do something like below. (The database way would obviously be a much better way, but this is just an example.)

class Regular
{
    public function View()
    {
        //Do the view stuff in here
    }
}

class Editor extends Regular implements Edit
{

}

class Reviewer extends Regular implements Review
{

}

interface Review
{
    public function AcceptChanges()
    {
        //Do the accept changes here
    }
}

interface Edit
{
    public function MakeChanges()
    {
        //Do the make changes stuff here
    }
}


class Creator extends Regular implements Edit, Review
{
    public function ChangePermissions()
    {
        //Do the change permissions stuff here
    }
}
Flipper
  • 2,589
  • 3
  • 24
  • 32
  • The problem I have, though, is groups of users (moderators, trusted, etc. like on Stack Overflow). – Ry- May 14 '11 at 22:51
  • @minitech What do you mean? You would make a rank called Moderators and then set everybody's rank id to that specific rank. Next just do an SQL query to get all of the users in that group. – Flipper May 14 '11 at 22:59
  • 1
    @Flipper forward thinking, you would have to add a new DB column everytime a new type of permission is needed. – dqhendricks May 14 '11 at 23:19
  • @dqhendricks Yes you would, but there really is not another way that would be as efficient. – Flipper May 14 '11 at 23:33
  • 5
    @Flipper that's a pretty bold statement for any peice of code. – dqhendricks May 14 '11 at 23:39
  • Well, the problem is that the rankings are reputation-based. Ideally, I'd like a structure similar to a hash or dictionary, but with ranges, then with special exceptions like Administrators and the creator of the project, particular user ids, etc. – Ry- May 15 '11 at 00:17
  • @minitech I am sorry, but I am just not understanding your question. Maybe somebody else could explain what you mean better because it just does not seem to relate to your original question completely. – Flipper May 15 '11 at 00:21
  • I've edited my question, sorry - I didn't completely explain that last part. I basically want what SO has. – Ry- May 15 '11 at 00:39