Managing authentication on a per page basis - Discussion

While I am fully capable of building a login/authentication system in PHP and MySQL I have never actually stepped back and thought about the way I handle authentication on a per page basis. Generally I will just have a required file that checks for a specific value in a session variable and if authenticated allow the page to continue or if the authentication fails then produce an error.

I am running this on a Virtual Server so sessions themselves should be pretty secure however I am not convinced that this is a particularly efficient system, certainly not as good as it could be, I’m sure.

I don’t think posting any code is needed for a discussion on this subject as I am more interested in the theory behind the logic involved.

So, what I am interested in discussing is how do you manage authentication on a per page basis?

Include a file which uses existing cookies/sessions to check authentication?

Utilise a function that checks the database using a session id or something like the users IP or similar?

Thank you in advance for the time you may take in producing a reply.

How I do it on a per page basis is dependent on whether the user is first required to log in or not which you haven’t specified.

Terribly sorry, I thought it was implied, my appologies.

I have updated the original post with a more accurate/specific question, thank you in advance for any further input you put into the thread.

Edit,

Evidently I cannot edit my original post.

Please note, I am interested in the above question in an environment where the user is required to be logged in on the specific page in question, as implied in the first portion where I am mentioning how I check if the user is logged in continue, if not chuck an error.

Thanks.

I’m not sure whether I follow “per page”, what exactly do you mean.

Are you saying so some pages require you to be logged in and some don’t or some pages require specific permissions to view?

The way my framework functions is kind of like this:

index.php (entry script)
–> Include the core framework
-----> Initialize the system (fetch settings, config, initialize the template engine etc. the global stuff thats needed all the time)
-----> Establish a DB Connection
-----> Handle user authentication (sets up the user be they a member or guest, grabs their permissions (granular))
-----> Fetch the bootstrapper for a given ‘component’ or ‘module’ (i.e. articledisplay)
-----------> Include the backend classes for this ‘component’ or ‘module’ and initialize/process whatever it needs to in the pre process
-----------> Checks permissions, does the page stuff or whatever it needs to do based on the rules for that module
-----> The UI is constructed and outputted via the template engine.

So I have a granular permissions system so you have a usergroup structure thats something like this:

USERGROUP (i.e. member)
— Array of Permissions

PERMISSION
— UserID
— Array of Permissions

PERMISSION overrides USERGROUP, though they have the same perms. So the USERGROUP itself is the “default” permission set for a given user (based on the users group) but you have PERMISSIONS which is a per user override, so a particular user could be a “Member”, but certain permissions are adjusted specifically for that user.

The permissions themselves are somewhat multi-dimensional, so you not only have linear permissions (using a forum as an example) like “view forum” and “post thread” but a copy of those permissions (in both USERGROUP and PERMISSION) for each individual forum.

So if you had 8 forums, 1 of them is only visible to members, 2 are only visible to administrators you can do that, or you could specify select users (say an administrator forum for two of your admins, who are the head honcho’s or a VIP forum).

Then at the script level, each module has a set of permissions that are used, when the user is signed in, the permissions are loaded in; internally there are only one set of permissions (one array), which set depends on what exists (i.e. if a permission (custom) set exists they are used, else the usergroup default are used).

The module then checks the users permissions whenever the user attempts to commit an action. If the user doesn’t have permission to do it, in a messaging class there are a bunch of “message” methods, one of which is “printNoPerission()”, which is called. This stops the process and displays the no permission message. The exact wording of which is decided by a parameter passed to the method, along with a parameter of whether to offer login (in which case a login screen or link is available if they are a guest).

The way login authentication works is something like this (there are some nuances of my authentication system that are specific to my platform, logins are session and database backed, using a cookie for persistent logins):

  1. User has a cookie which contains the login credentials (in key form), this is for persistent logins
  2. A matching session (which is actually optional, you can bypass this and use database session and vice versa, so ignore the DB session)
  3. A matching database session

The authentication system checks for a session and compares the keys to authenticate, if the login session is valid and not expired then the user is logged in, otherwise their login is expired and they are a guest.

During login the permissions are set, so its not as simple as “logged in” or “not logged in” or “member” or “guest” as the usergroups are both extendable and you can create custom groups. There is more to it than that, but I think that describes it sufficiently enough to get a “model” across. Of course how you authenticate the session, how you structure keys and how you prevent full authentication on a per page load basis (if you want to prevent it at all) will be system/framework dependent.

You can go simple and just use a session to maintain the users login, but for my framework its a bit too simplistic. Also there are a few issues with just doing that, it needs to be validated somewhere and hijacking needs to be prevented somewhere.

Wow, fantastic reply, thank you so much for the time and effort put into it!

By “per page basis”, sorry for the confusion, I simply mean ‘when a page (any particular page) loads how is authentication handled’ as presumably any site that handles authentication will do so on each page of the site and generally speaking (as far as I am aware at my level of knowledge) regardless of what authentication is required to access a page it is still processed the same way?

User is unknown,
User is a registered member,
User is a registered contributor/moderator/editor,
User is a registered administrator.

Page requires no authentication,
Page requires member status - get authentication information, if user is equal to or greater than a member continue,
Page requires contributor/moderator/editor status - get authentication information, if user is equal to or greater than a contributor/moderator/editor continue,
Page requires administrator status - get authentication information, if user is equal to an administrator continue.

Or has that confused things further? Thanks again, I didn’t think I was going to get any replys hehe.

First, no problem.

Second, what you describe there is a basic authentication and permissions system.

To answer your question:

  1. The authentication will happen globally, so exists on all pages. Whatever mechanism you use for authentication will process everywhere so you will have access to your usergroup information for each user on ever page. Then every page can allow access or prevent access (entirely or to particular features of that page) based on the permissions within the usergroup.

  2. How you authenticate will be dependant upon your system, normally you’d have some kind of architecture where you have a bootstrap mechanism that runs from index.php (no separate root php files for each page), within that process you’ll initialize a framework that handles authentication. Authentication will usually be a combination of session and cookie.

Typically a user accounts credentials will consist of something like:

  • UserID (unique user id)
  • Username
  • Password (encrypted hash)
  • Salt (a salt value based on something account specific, for example join date)

The salt is used as a key against the password hash (combined they create a new hash which is what you store for the password and use to authenticate).

You do this on every script load to authenticate. Also you can have a session hash key which is compared to validate the session for added security.

Now what you describe is a really basic system and one I would avoid, you should go granular.

With a granular system you don’t handle permissions as “isAdmin”, “isGuest”, “isModerator” etc.

Instead you have a usergroup table with more specific permissions, something like this:

USERGROUP (table)

  • usergroupid (INT) Primary Key
  • grouptitle (VARCHAR) // Name of the usergroup
  • isBanned (BOOL) // A flag for whether the group is “banned”
  • isGuest (BOOL) // A flag for whether the group is for guests
  • isMember (BOOL) // A flag for whether the group is for members
  • isModerator (BOOL) // A flag for whether the group is for moderators
  • isAdministrator (BOOL) // A flag for whether the group is for administrators
  • Cutting away from the fields for a moment as there are more, but something has to be said *
    Those isBanned, isGuest, isMember fields are not for permissions, they are for hierarchy (exception with Banned, if thats true you lockout). Basically they add an order to things. i.e. isAdministrator can perform allowed actions on any group. isModerator can perform allowed actions only on isMember, isGuest and isBanned (maybe isModerator depending on your architecture).

In other words, it creates the user level. But does not define what you can actually do, you should have permissions for this. Take a website with a forum and news articles and pages and a CMS. I’ll keep it simple:

  • viewPage (BOOL) // Can the usergroup view pages on the front site
  • createPage (BOOL) // Can the usergroup create pages (CMS)
  • editPage (BOOL) // Can the usergroup edit pages (CMS)
  • deletePage (BOOL) // Can the usergroup deletePages (CMS)
  • viewArticle (BOOL) // Can the usergroup view articles
  • createArticle (BOOL) // Can the usergroup create articles
  • editArticle (BOOL) // Can the usergroup edit articles
  • deleteArticle (BOOL) // Can the usergroup delete articles
  • commentArticle (BOOL) // can the usergroup comment on articles
  • viewForum (BOOL) // Can the usergroup view forums
  • postThread (BOOL) // Can the usergroup post threads
  • postReply (BOOL) // Can the usergroup post replies
  • editPost (BOOL) // Can the usergroup edit posts (moderation)
  • editOwnPost (BOOL) // Can the usergroup edit their own posts
  • deletePost (BOOL) // Can the usergroup delete posts (moderation)
  • deleteOwnPost (BOOL) // Can the usergroup delete their own posts
  • closeThread (BOOL) // Can the usergroup close threads
  • openThread (BOOL) // Can the usergroup open their own threads
  • These are all Boolean, true/false fields. You can have other stuff like, if you have a private messenger.
  • pmQuota (INT) // Maximum messages the user can have in their inbox

Then the usergroups themselves:
Banned (no permissions, is banned type)
Guest (is guest type, has read type fields to true, others to false)
Member (is member type, set to true/false for what you want members to do)
Moderator (is moderator type, set to true/false for what you want mods to do)
Administrator (is admin type, set to true/false for what you want admins to do)

Thats granular, your permission are details (like grains for each feature). It gives more control over permissions and allows you to flex your site/system more and makes things less “error prone”.

You can then have levels to your permissions (different layers). Take a forum, posting rights. Most of your forums are open to thread creation and reply. But you have an announcements forum, which only moderators and admins can create threads, members can reply.

table:
FORUMPERMISSION

  • permissionid (a unique id for the permission layer)
  • forumid (the forum this layer is for)
  • usergroupid (the usergroup this layer is for)
  • viewForum (BOOL) // Can the usergroup view forums
  • postThread (BOOL) // Can the usergroup post threads
  • postReply (BOOL) // Can the usergroup post replies
  • editPost (BOOL) // Can the usergroup edit posts (moderation)
  • editOwnPost (BOOL) // Can the usergroup edit their own posts
  • deletePost (BOOL) // Can the usergroup delete posts (moderation)
  • deleteOwnPost (BOOL) // Can the usergroup delete their own posts
  • closeThread (BOOL) // Can the usergroup close threads
  • openThread (BOOL) // Can the usergroup open their own threads

If a record exists here for a specific forum, this set overrides the usergroups permissions, if a record doesnt exist (for the forum AND usergroup - joined key) then the usergroups permissions are used.

So for the announcements forum (forumid 1) you’d have a record for member which disabled thread posting and enabled replies and view. This then allows members to view and reply to threads but not create them.

Thats adding layers to granularity.

Then in your scripts you would check the permissions themselves.

i.e. on viewing a thread:


if($permission['viewThread'] == false)
{
   $errorManager->printNoPermission(); // Prints you do not have permission to view this thread
}

You should at least have granularity (in my opinion of course). Having built sites with granularity for so long, I cannot imagine going back.

Is this the kind of thing your wanting to know/get feedback on?

Outstanding, it makes perfect sence, thank you.

Is this the kind of thing your wanting to know/get feedback on?

Absolutely. Basically what has happened recently is bit of a personal melt down. I thought I knew allot more than I do and it is recently that I have realised just how much knowledge and ability I lack in PHP particually.

I work full time where my main role is support work, anything from simple PHP errors to full HTML/CSS redesign so I have a hand in all aspects of a PHP based website from creation to maintenance. I also run my own part time business working mainly with small businesses and have undertaken the task of creating my own basic CMS/Framework to base all my client sites off of for speed and organisational reasons along with giving the client the ability to modify their site without having a massive 3rd party CMS and without me needing to learn how to modify it (giving me total control over my own CMS, not partial control over a system I do not know very well).

It has gone great so far, the system works how it should although not very feature rich at the moment. The sites I have running on it are working well and the back end is fairly simple. It was during a look over my current code recently when I had this realisation that I am actually a terrible programmer.

So that’s what has sparked these threads, I have figured it is easier to start from the beginning with my knowledge and try to second guess everything I program with the intention of learning PHP effectively and grow into a competent programmer and maybe even switch career paths into a more programming oriented role as I really enjoy it.

I am really keep to develop my general understanding of PHP as a language, object oriented programming (I understand the principals but struggle with the implementation), theory and logic of PHP applications (I.E. This thread) etc.

Well good luck!

With OO, you should get to grips with it. If you struggle with OO concepts, even loose use of OO will benefit you as it teaches re-usability of code and code structure.

What I would recommend is to invest some time into learning how to put together a re-usable OO framework for your websites, one that works well for you. I don’t mean a fully fledged CMS but a basic framework you can build off.

Like your core, auth system, permissions system, bootstrap system and template engine.

So you have core layer, bootstrap and module layer and presentation layer. Basically an MVC architecture of sorts. You can implement it how you like, the importance is that the “concept” is followed. There are various “methodologies” a simple google will reveal them.

I don’t like the Joomla/Drupal styles of MVC, I find them too fragmented, I prefer a tighter approach, more like this:

  • Index

  • Includes/core

        • Contains the core framework and template engine (for the presentation layer)
  • Modules

        • Contains the bootstraps for the modules
  • Includes/modules

        • Contains the classes for each module
  • Templates

        • Contains your styles/templates

That kind of thing., You essentially have one index.php, a class core for the core parts of the framework, bootstraps for the modules (I’ve seen these as classes or procedural scripts that access class methods), pure classes are stricter and more “correct”, but honestly you do what feels best for you. As long as you follow good standards and OO practices throughout.

Then you have classes for each module that present the functions of each module.

You then have the presentation layer parts separated (i.e. a template engine), I use a bespoke template engine, others use 3rd party engines such as Smarty. Up to you what you use.

That kind of architecture is where you want your starting point to be, to learn that and OO will kind of just connect and click.

Thank you once again FizixRhichard.

One last question, have you ever used killerphp.com? If so, is the quality of their training of good standard, in your opinion?

You have been an amazing help, you seem to be able to talk in a way that invokes thought but is easy to follow and digest, I will be re-reading this thread a few times I am sure! The methods you speak of are not far off what I have, in terms of logic and process, I just need to bring the programming itself up to a decent standard and start planning an OO framework and start playing (thanks for the idea, love it!).

I cant express how grateful I am for your input.

Never used killerphp so I cant comment on them. But no problem with the help.

I would say to take a peep into some good applications to see how they are structured and how they do things, there are finer nuances to security and logins than I’ve described here. So its worth really reading up.

Thanks :slight_smile:

I use acl. So every content object knows which user/usergroup is allowed to add, edit, delete or view it. The permissions are stored in a database table (basically a bridge table between the user or usergroups table and all the content tables with an extra field to specify the type of content and another field to specify the permissions (add,edit,delete,view))

Aslong as my database password is safe the system should be safe :smiley:
And the login procedure should be safe ofcourse.

Thank you brense, it certainly seems like split tables are the way to go, especially with permissions. My current approach has been just a lonely value in the users table which tells me in the user is banned(0) registered(1) admin(2).

I used to use access control lists, in the traditional form (but backed by usergroups), something like this:

Tables:
user(userid, usergroupid, username, …)
usergroup(usergroupid, title, tier, …)
permission(permissionid, userid, usergroupid, entityid, permission, rule, …)

So your user would have a usergroup, (these I would create, what they were would be system dependent but normally guest, banned, member, admin)

Then you have the permissions table, which I’ll explain:

  • permissionid is a unique id for that entry
  • userid is the users unique id (if applying a permission to a specific user, their userid goes there, otherwise userid is 0)
  • usergroupid is the usergroups unique id (if applying a permission to a usergroup, the usersgroups usergroupid goes there, otherwise it is 0)
  • entityid is the reference to the object or collection you are applying the permission to (this was optional under my system as perms could be global)
  • permission is a hook for the permission so you can reference it in code directly
  • rule is the permission value, normally a bool.

Now, that method works fine and it served me well, BUT I did find that on larger websites it lead to a rather chunky permissions table, adding new permissions would require writes or defaulting and it introduced an overhead. I started to just dislike it, so went for a permissions system in this format (which does the same thing really):

permission1, permission3 etc are just blurbs for permissions, they all had meaningful names.

user(userid, usergroupid, username, …)
usergroup(usergroupid, hook, title, tier, permission1, permission2, permission3, …)

Then I would have an overrides table where needed like this
userpermission(userid, tier, permission1, permission2, permission3, …) // For user specific permission overrides
forumpermission(forumid, usergroupid, userid, viewforum, viewthread, postthread, postreply, editpost, deletepost, …) // For content specific overrides (i.e. forum)

^ that could be combined into a contentpermission with a couple of fields (contenttype, contentid)

ContentType being say “forum”, “article”. Would essentially be the module or class.
ContentID would be the ID of the content (i.e. forumid or articleid or categoryid) or the node

I just found this more pleasant to work with and it was a bit faster.

But then how do you handle locked forum posts for example?

I find that it is safer (and faster) to have my content handle permissions rather then my users. This means i dont have overhead on my users table (or content for that matter). The chunky permissions table is no problem if you have good indexes. MySQL can handle hundreds of thousands of records with no problems. I never had performance issues.

But I can see your point. You loose track of your permissions table (it gets a life of its own). No human will be able to read it. But the system can :smiley:

thread(threadid, forumid, open, subject, postdate, …)

open is a bool

Then if you want certain groups to be able to post in locked threads. Use a permission for that.

I suppose I like traditional usergroups (as the base permissions set) with a content layer and user layer for specific permissions (i.e. forum perms, user specific perms) which override the usergroup default.

Neither do I as the system is exactly the same as what you mention, just consolidated. I used to use a traditional ACL system, I just wound up consolidating the permission data for easier maintenance and using layers.

This is true, but consolidated data will always be faster and easier for the developer to handle.

Which is fine, but for me, that introduced a problem when it came to changing the permissions tables, you could tie yourself into a bit of a knot when it comes to converting the existing perms to your new schema.

Anyway, its all personal preference really. Both methods can achieve exactly the same thing and be secure. If you can’t make one secure you wont make the other secure.