草庐IT

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

coder 2023-10-14 原文

我是PHP和MYSQL的新手,试图创建一个网站,用户可以用来将数据输入数据库。我要尝试的一个示例是为各家银行及其提供的各种服务提供数据库。例如,花旗银行的用户在我的网站上创建了一个帐户,他将输入自己的LoginID,Password,Email和姓名的银行(在本例中为花旗银行)。

成功创建帐户并登录后,他将成为花旗银行的“管理员”帐户,并有权创建,删除,插入和查看花旗银行中的所有数据。 他还可以进一步创建和删除出口,以及为该出口创建/删除子用户帐户。该子用户帐户将拥有管理帐户的所有权利减去有权创建其他子用户,但仅限于管理员帐户和子帐户都可以通过该网站登录。

我列出了我认为帐户需要的权利:

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

我目前正在考虑为管理员帐户实现下表:
Admin
+----------+-----------+------------+------------+
|  BankID  | BankName  |  UserName  |  Password  |
+----------+-----------+------------+------------+
|  1       | Citibank  |  CitiAdmin |  PassCiti  |
|  2       | StanChart |  StanAdmin |  PassStan  |
|  3       | HSBC      |  HSBCAdmin |  PassHSBC  |
+----------+-----------+------------+------------+

当BankID的类型为SERIAL时,而BankName,UserName和Password将由用户在创建帐户时输入。我之所以不将上表分为2个表,其中一个表包含BankID和BankName,其他包含用户名和密码的将是易于使用,因为我认为将它拆分是不必要的,并且对其进行了过度规范化。

下表适用于子用户帐户:
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    |
+------+------------+--------------+-------------+

这样,在用户登录时,我将从$ _POST [User]和$ POST [Pass]获取用户条目,并与从查询中提取的数据进行匹配
$query="SELECT Username AND Password FROM Admin AND SubUsers";

如果存在匹配项,则该用户将登录。通过这样做,我可以实现第一级验证,其中只有注册用户才能访问数据库。

但是我将如何限制对Admin帐户和SubUser帐户的访问。Admin帐户只能访问与他的银行有关的数据,而SubUser帐户只能访问与他的出口有关的数据。

我曾考虑过使用PHP session 在登录时通过更改登录查询来记录有关用户的数据。

$ query =“从管理员和子用户中选择用户名和密码”;

到一个查询,该查询首先从Admin中选择用户名和密码,然后运行$ _POST [User]和$ _POST [Pass],如果没有匹配项,它将从SubUser中提取用户名和密码并重复该过程,并且将结果记录到 session 中,具体取决于匹配是在Admin表还是SubUser表中发生的。

但是,这样做只会更改用户登录后可用的网页,而不会更改他们对数据库本身的实际访问权限。我能想到的使用此方法的最接近解决方案是为用户创建一套全新的网页,具体取决于无论用户是Admin还是SubUser,我都不愿意这样做,因为我还是编程新手,而增加网页数量只会增加不可避免地显示的错误数量。

还有其他任何方法来限制用户对数据库的访问,或者是否有其他解决方案来优化我正在尝试做的事情?

我看过How to configure phpMyAdmin for multiple users - each with access to their database only,但对我来说有点技术性,似乎正在处理用户对数据库而不是表的访问。

任何建议/帮助/指导将不胜感激。

最佳答案

这是一个有趣而彻底的问题。它不是那种需要一本书才能彻底回答的类型。我佩服你的野心。

首先正确设计。

  • 问问自己用户可能需要执行哪些操作并给他们命名。将特权名称存储在表中后,可以根据需要将它们分配给角色或用户。您可以通过在执行每个操作之前检查是否应用了适当的特权,或者通过将每个操作编写为包含特权身份验证的功能来对在PHP级别执行每件事的能力进行身份验证。
  • 在每个表中将银行ID和分支ID作为外键。这样,您只需将bankid和branchid作为WHERE子句的“AND”添加项包括在内。这样一来,您只需要一个数据库,但是您可以控制谁使用智能编写的SQL来查看内容。
  • 如果您需要用户能够对其数据运行SQL,请确保所有查询都通过添加必需的AND(bankid ='%s'AND branchid ='%s')子句的函数运行。这有效地分离了数据。如果需要的话,您可以添加对返回数据的检查,还可以考虑使用加密(每个存储库使用不同的密钥),尽管这有点远。

  • 这几乎就是应用程序层控制的含义。 PHP应用程序根据存储的特​​权选择您有权访问的数据。给他们有意义的名字和冗长的描述,我无法强调计划您的特权的重要性。当您开始时,似乎有很多工作要做,但是却有所作为。当然,不必为每个用户创建一个新的数据库。不必担心填写您的SERIAL ID-BIGINT可以在200,000多年的时间内每秒处理100万笔交易。

    设计完成后,身份验证将成为下一个障碍。我认为您应该在写任何花哨的内容之前先执行此操作,因为确实很难做到正确。

    我要做的是:

    收集银行,分行和用户名(允许它们在您的HTML中自动完成),然后输入密码。
    将密码存储为SHA1或MD5哈希。
    通过身份验证后,您可以将用户编号,银行和分支机构编号弹出​​到$ _SESSION中,然后可以在以后轻松地将它们检索以用于SQL。
    为了提高安全性,尽管增加了复杂性,但是您也可以根据需要从数据库中选择这些数字。有些建议将它们存储在单独的 session 表中。

    关于如何设计此类项目还有很多要说的内容,而且很多内容都可以在此站点的其他地方找到,所以我不再赘述。请随时询问是否不清楚。

    我希望这有帮助。

    编辑:

    处理特权。

    没有简单的方法来处理特权。我对所有页面都使用一个头文件,该文件会自动提取特权信息:

    一种。标识用户,通常从$ _SESSION中选择用户编号。
    b。从数据库表users_priveleges中识别用户的特权。
    C。创建一个包含特权名称的数组。
    d。对于每个通过数组进行比较,以便在需要特权请求操作时进行比较。

    此方法需要很多表,也许可以满足您的需要,但是如果您具有以下表(仅在此处提供骨架详细信息),则该方法几乎可以无限扩展:
    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.
    

    您要做的是在role_priveleges表中输入一行,将角色链接到特权。对角色所需的所有特权重复上述步骤。可能很多。没问题

    添加用户后,您将授予他们一个角色。然后,我读取Roles_priveleges表,并向 super 用户显示可能的角色列表作为复选框,如果通常将授予特权,则将其打勾,否则将其选中。 super 用户根据需要从列表中取消选择或选择,然后保存列表。
    保存列表时,我将users_priveleges表中该用户的所有条目标记为非 Activity 状态,并为每个特权插入新行。这使您可以跟踪更改,并且重要的是,可以查看特权的审核日期,即使它们没有更改也是如此。它最终不会使用太多数据,因为users_priveleges中的每一行都包含三个Bigint,一个 bool(boolean) 值和两个日期。

    如果您永远不想授予一个用户通常不会出现的特权,那么您可以简单地使用role_priveleges和users_roles。这最小程度地减少了数据消耗,但灵活性却大大降低了。

    我将承认我所描述的方法有些不雅,但是它提供了非常好的基于角色和基于用户的特权管理,同时将数据库保持在第4范式或更高级别。恕我直言,值得付出更多的努力,因为您的应用程序有一天会变得更大,并且现在添加这些东西要容易得多,而不是以后添加。
    同样,从初学者的角度来看,在进行一些困难之前,创建虚拟数据并确保SQL连接正常工作非常容易。

    关于php - 登录时验证用户并授予他们有限的数据库权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16757076/

    有关php - 登录时验证用户并授予他们有限的数据库权限的更多相关文章

    1. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

      我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

    2. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

      我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

    3. ruby - RVM "ERROR: Unable to checkout branch ."单用户 - 2

      我在新的Debian6VirtualBoxVM上安装RVM时遇到问题。我已经安装了所有需要的包并使用下载了安装脚本(curl-shttps://rvm.beginrescueend.com/install/rvm)>rvm,但以单个用户身份运行时bashrvm我收到以下错误消息:ERROR:Unabletocheckoutbranch.安装在这里停止,并且(据我所知)没有安装RVM的任何文件。如果我以root身份运行脚本(对于多用户安装),我会收到另一条消息:Successfullycheckedoutbranch''安装程序继续并指示成功,但未添加.rvm目录,甚至在修改我的.bas

    4. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    5. jquery - 如何将 AJAX 变量从 jQuery 传递到他们的 Controller ? - 2

      我有一个电子邮件表格。但是我正在制作一个测试电子邮件表单,用户可以在其中添加一个唯一的电子邮件,并让电子邮件测试将其发送到该特定电子邮件。为了简单起见,我决定让测试电子邮件通过ajax执行,并将整个内容粘贴到另一个电子邮件表单中。我不知道如何将变量从我的HAML发送到我的Controllernew.html.haml-form_tagadmin_email_blast_pathdoSubject%br=text_field_tag'subject',:class=>"mass_email_subject"%brBody%br=text_area_tag'message','',:nam

    6. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

      因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

    7. ruby - Rails -- :id attribute? 所需的数据库索引 - 2

      因此,当我遵循MichaelHartl的RubyonRails教程时,我注意到在用户表中,我们为:email属性添加了一个唯一索引,以提高find的效率方法,因此它不会逐行搜索。到目前为止,我们一直在根据情况使用find_by_email和find_by_id进行搜索。然而,我们从未为:id属性设置索引。:id是否自动索引,因为它在默认情况下是唯一的并且本质上是顺序的?或者情况并非如此,我应该为:id搜索添加索引吗? 最佳答案 大多数数据库(包括sqlite,这是RoR中的默认数据库)会自动索引主键,对于RailsMigration

    8. ruby-on-rails - 如何让 datamapper 与 postgresql 数据库一起工作? - 2

      我已经找到了几个使用datamapper的示例,并且能够让它们正常工作。不过,所有这些示例都是针对sqlite数据库的。我正在尝试将数据映射器与postgresql一起使用。我将datamapper中的调用从sqlite3更改为postgres,并且我已经安装了dm-postgres-adapter。但它仍然不起作用。我还需要做什么? 最佳答案 与SQLite不同,PostgreSQL不将数据库存储在单个文件中。在你拥有createdyourdatabase之后,尝试这样的事情:DataMapper.setup:default,{:

    9. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

      我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

    10. ruby - HTTP 请求中的用户代理,Ruby - 2

      我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

    随机推荐