简体   繁体   中英

Validating users upon login and giving them limited rights to database

I'm new to PHP and MYSQL, trying to create a website which users can use to input data into a database. An example of what i'm trying to do would be a database for various banks and the various services they provide.For example, a user from Citibank creates an account on my website, he will enter his LoginID,Password,Email & the name of his bank(which would be Citibank in this case).

Upon successfully creating an account and logging in, he would be the "Admin" account for Citibank with the rights to Create,Delete,Insert & View all data from Citibank ONLY. He would also be able to further create & delete Outlets, and create/delete a SubUser account for that outlet.The SubUser account would have all the rights the Admin account would have minus the right to create further SubUsers, BUT restricted to only the Outlet it is in charge of.Both Admin and Sub accounts would be logging in through the website.

I've listed down the rights which i think the accounts would need:

Rights to database
SELECT,INSERT,UPDATE,DELETE,(JOIN?)

I am currently thinking of implementing the following table for the Admin account:

Admin
+----------+-----------+------------+------------+
|  BankID  | BankName  |  UserName  |  Password  |
+----------+-----------+------------+------------+
|  1       | Citibank  |  CitiAdmin |  PassCiti  |
|  2       | StanChart |  StanAdmin |  PassStan  |
|  3       | HSBC      |  HSBCAdmin |  PassHSBC  |
+----------+-----------+------------+------------+

Where the BankID would be of type SERIAL, while the BankName,UserName and Password would be entered by the user upon creation of his account.The reason why i do not split the above table into 2 tables with one containing the BankID and BankName and the other containing Username & Password would be for ease of use as i feel that splitting it up would be needless, and be over-normalising it.

While the following table would be for the Subuser accounts:

SubUsers
+------+------------+--------------+-------------+
|  ID  |  OutletID  |  Name        |  Password   |
+------+------------+--------------+-------------+
|  1   |  1         |  CitiSub1    | PassSub1    |
|  2   |  1         |  CitiSub2    | PassSub2    |
|  3   |  2         |  StanSub1    | PassSub1    |
|  4   |  2         |  StanSub2    | PassSub2    |
|  5   |  3         |  HSBCSub1    | PassSub1    |
|  6   |  4         |  HSBCSub2    | PassSub2    |
+------+------------+--------------+-------------+

By doing this, upon user login, i would get the userentry from $_POST[User] and $POST[Pass] and match if against the data drawn from the query

$query="SELECT Username AND Password FROM Admin AND SubUsers";

and if there is a match, the user will be logged in.By doing this i am able to achieve a first level of verification where only registered users are able to access the database.

However how would i restrict access to both the Admin account, AND the SubUser account.The Admin account would only be able to access data pertaining to his Bank, and the SubUser account would only be able to access data pertaining to his Outlet.

I've considered using PHP sessions to perhaps record data about the user when logging in by changing the login query from

$query="SELECT Username AND Password FROM Admin AND SubUsers";

to a query that first selects Username and Password from Admin, and runs the $_POST[User] and $_POST[Pass] through it, and if there isnt a match it would draw Username and Password from SubUser and repeat the process, and would log a result into the session depending if the match happened in the Admin table or SubUser table.

However,doing this would only change the webpages available to the user upon login and not their actual access to the database itself.The closest solution i can think of using this method would be to create a brand new set of webpages for the user depending on whether the user is an Admin or SubUser, which i would rather NOT do as i am still new to programming, and increasing the number of webpages would only increase the number of bugs that will ineveitably show up.

Are there any other methods to restrict user access to the database, and or other solutions to optimise what i'm trying to do?

I've looked at How to configure phpMyAdmin for multiple users - each with access to their database only but it's a little too technical for me and seems to be dealing with user access to databases instead of tables.

Any advise/help/guidance will be MUCH appreciated.

What an interesting and thorough question. It is rather of the type that requires a book to answer thoroughly though. I admire your ambition.

First design it properly.

  1. Ask yourself what actions users might need to do and give them a name. Once you store the privelege names in a table, you can assign them to roles or users as required. You authenticate the ability to do each thing at PHP level, either by checking before each action that the appropriate privelege is applied or by writing each action as a function that includes authentication of priveleges.

  2. Put the bank id and branch id as Foreign Keys in each table. That way you simply include the bankid and branchid as 'AND' additions to your WHERE clause. This wa you need only one database but you control who gets to see what using intelligently written SQL.

  3. If you need the users to be able to run SQL on their data, ensure that all queries are run through a function that adds the requisite AND (bankid='%s' AND branchid='%s') clause. This effectively separates the data. You can add a check of your returned data if you need to and also consider using encryption (different key for each bank) though that is going a bit far.

This pretty much is what is meant by application-layer control. The PHP application selects what data you have access to based on stored priveleges. I cannot re-inforce how important it is to plan your priveleges, given them meaningful names and verbose descriptions. It seems a lot of work when you start but it makes the difference. it certainly beats having to create a new database for each user. Don't worry about filling up your SERIAL ids - a BIGINT can handle a million transactions per second for over 200,000 years.

Once designed, authentication is the next hurdle. I reckon you should do this before you write anything fancy as it's really quite hard to get right.

What I would do is:

Collect bank,branch and username (allow these to autocomplete in your HTML) and then password. Store the password as an SHA1 or MD5 hash. Once authenticated, you pop the usernumber, bank and branch numbers into your $_SESSION They can then easily be retrieved for SQL later. For added security, though increased complexity, you can also pick these numbers out of the database as required. Some recommend storing them in a separate session table.

There is so much more to say about how to design this sort of project and much of it can be found elsewhere on this site so I will not prattle on further. Please feel free to ask if anything is unclear.

I hope this helps.

EDIT:

Handling the priveleges.

There is no simple way to handle priveleges. I use a single header file for all my pages that automatically extracts privelege information:

a. Identify the user, usually picking the usernumber from $_SESSION. b. Identify the user's priveleges from the DB table users_priveleges. c. Create an array containing the privelege names. d. For Each through the array to compare whenever a privelege-required operation is required.

This method needs a lot of tables and is perhaps a bit advanced for your needs but if you have the following tables (skeleton details provided here only) it is pretty much infinitely expandable:

roles (role_id,rolename,role_detailed_description)
priveleges (privelege_id,privelegename,privelege_detailed_description)
users (user_id,user_details)
users_roles (user_id,role_id) (optional but a good idea)
users_priveleges (user_id,privelege_id) - priveleges granted to each user
roles_priveleges (role_id,privelege_id) - the priveleges each role has.

What you do is enter a line in the roles_priveleges table linking a role to a privelege. Repeat for all priveleges required by the role. Could be a lot. Not a problem.

When a user is added, you grant them a role. I then read the roles_priveleges table and present the super-user with a list of possible roles as checkboxes, ticked if the privelege would usually be granted, not if otherwise. The super-user deselects or selects from the list as required then saves the list.
On saving the list, I mark all entries for that user in the users_priveleges table as inactive and insert a new line for each privelege. This allows you to track the changes and, importantly, the date the priveleges were reviewed, even if they were not changed. It does not end up using much data as each line in users_priveleges consists of three Bigints,a bool and 2 dates.

If you never want to grant one user a privelege that their role would not normally posess then you can simply use roles_priveleges and users_roles. This is minimally less data-hungry but is notably less flexible.

I will concede the method I have described is a little inelegant but it provides very good role based and user based privelege management whilst keeping the DB in the 4th Normal Form or higher. IMHO it is worth going the extra mile because your application will one day be bigger and it is far easier to add this stuff now rather than later. Also, from a beginner's point of view, it is very easy to create dummy data and ensure your SQL joins are working before you embark on something a bit harder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM