简体   繁体   English

登录时验证用户并授予他们对数据库的有限权限

[英]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. 我是PHP和MYSQL的新手,试图创建一个用户可以用来将数据输入数据库的网站。 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). 我正在尝试做的一个例子是各种银行的数据库及其提供的各种服务。例如,Citibank的用户在我的网站上创建一个帐户,他将输入他的LoginID,密码,电子邮件和名称他的银行(在这种情况下将是花旗银行)。

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. 他还可以进一步创建和删除Outlets,并为该插座创建/删除SubUser帐户.Sub用户帐户将拥有Admin帐户所具有的所有权利减去创建更多SubUsers的权利,但仅限于Outlet管理员和子帐户都将通过网站登录。

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帐户实现以下表格:

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. 如果BankID属于SERIAL类型,而BankName,UserName和Password将由用户在创建其帐户时输入。之所以我不将上表分成2个表,其中一个表包含BankID和BankName以及其他包含用户名和密码将是易于使用,因为我觉得拆分它是不必要的,并且过度规范化它。

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 通过执行此操作,在用户登录时,我将从$ _POST [User]和$ POST [Pass]获取userentry并匹配从查询中提取的数据

$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. 但是,我如何限制管理员帐户和SubUser帐户的访问权限。管理员帐户只能访问与其银行相关的数据,而SubUser帐户只能访问与其Outlet相关的数据。

I've considered using PHP sessions to perhaps record data about the user when logging in by changing the login query from 我考虑过使用PHP会话来记录用户登录时的数据,方法是更改​​登录查询

$query="SELECT Username AND Password FROM Admin AND SubUsers"; $ query =“SELECT用户名和密码来自Admin和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. 查询首先从管理员中选择用户名和密码,并通过它运行$ _POST [用户]和$ _POST [传递],如果没有匹配,它将从SubUser中绘制用户名和密码并重复该过程,并且将结果记录到会话中,具体取决于Admin表或SubUser表中是否发生匹配。

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. 但是,这样做只会在登录时改变用户可用的网页,而不会改变他们对数据库本身的实际访问权限。我能想到使用这种方法的最接近的解决方案是为用户创建一组全新的网页,具体取决于无论用户是Admin还是SubUser,我都不愿意这样做,因为我还不熟悉编程,增加网页数量只会增加无法显示的错误数量。

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. 我已经看过如何为多个用户配置phpMyAdmin - 每个用户只能访问他们的数据库,但它对我来说有点太技术性,似乎在处理用户访问数据库而不是表。

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. 将privelege名称存储在表中后,可以根据需要将它们分配给角色或用户。 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. 您可以通过在每个操作之前检查是否应用了适当的privelege,或者通过将每个操作写为包含priveleges身份验证的函数来验证在PHP级别执行每个操作的能力。

  2. Put the bank id and branch id as Foreign Keys in each table. 将bank id和branch id作为Foreign Keys放在每个表中。 That way you simply include the bankid and branchid as 'AND' additions to your WHERE clause. 这样,您只需将bankid和branchid包含为WHERE子句的“AND”添加项。 This wa you need only one database but you control who gets to see what using intelligently written SQL. 这只需要一个数据库,但你可以控制谁可以看到使用智能编写的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. 如果您需要用户能够在其数据上运行SQL,请确保所有查询都通过添加必需AND(bankid ='%s'和branchid ='%s')子句的函数运行。 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. PHP应用程序根据存储的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. 不要担心填写SERIAL ID - BIGINT可以处理超过20万年的每秒百万次交易。

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. 收集银行,分行和用户名(允许这些在您的HTML中自动完成),然后密码。 Store the password as an SHA1 or MD5 hash. 将密码存储为SHA1或MD5哈希。 Once authenticated, you pop the usernumber, bank and branch numbers into your $_SESSION They can then easily be retrieved for SQL later. 一旦通过身份验证,您就可以将用户编号,银行和分支编号弹出到$ _SESSION中,然后可以在以后轻松检索SQL。 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. 没有简单的方法来处理priveleges。 I use a single header file for all my pages that automatically extracts privelege information: 我为所有页面使用单个头文件,自动提取privelege信息:

a. 一种。 Identify the user, usually picking the usernumber from $_SESSION. 识别用户,通常从$ _SESSION中选择用户编号。 b. Identify the user's priveleges from the DB table users_priveleges. 从数据库表users_priveleges中识别用户的权限。 c. C。 Create an array containing the privelege names. 创建一个包含privelege名称的数组。 d. d。 For Each through the array to compare whenever a privelege-required operation is required. 每当需要privelege所需的操作时,通过数组进行比较。

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. 你要做的是在roles_priveleges表中输入一行,将一个角色链接到一个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. 然后,我阅读roles_priveleges表,并向超级用户显示可能的角色列表作为复选框,如果通常会授予privelege,则勾选,否则返回。 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. 在保存列表时,我将users_priveleges表中该用户的所有条目标记为非活动状态,并为每个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. 它最终不会使用太多数据,因为users_priveleges中的每一行都包含三个Bigint,一个bool和两个日期。

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. 如果您永远不想授予一个用户他们的角色通常不会拥有的权限,那么您可以简单地使用roles_priveleges和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. 我将承认我所描述的方法有点不优雅,但它提供了非常好的基于角色和用户的privelege管理,同时保持DB在第4范式或更高。 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. 此外,从初学者的角度来看,创建虚拟数据非常容易,并且在您开始执行某些操作之前确保SQL连接正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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