在PHP和Javascript中实现用户授权

Jon*_*han 4 javascript php authorization

假设我有一个有效的会话和一个经过身份验证的用户,那么在使用PHP/MySQL后端的应用程序和一个繁重的JavaScript前端中实现用户授权有哪些方法呢?

我发现的大多数实现示例似乎都过于关注用户身份验证,而授权就是这样.例如,if语句检查用户的类型是否为admin.这对我来说似乎太过实施了.

在像我这样的实现中,无法知道用户在发起请求时所处的"页面".因此,由PHP确定的仅为某些用户提供某些内容的方法对于我需要做的事情而言过于宽泛.

理想情况下,每个实体都有一种基于用户明确或用户所在的组或类型的访问控制列表.

我去了一家当地的书店,花了一个下午的时间浏览他们在PHP,MySQL和JavaScript上的所有内容.令人惊讶的是,大多数书籍几乎没有关于用户授权的任何内容.这吓坏了我!这必须由构建使用AJAX的大型Web应用程序的任何人解决,我似乎无法找到让我入门的东西.

我会很感激任何反馈,经验,技巧等(关于这个主题的任何书籍?)

Dav*_*her 7

PHP安全性似乎陷入了单一密码的黑暗时代,为一类特定页面的单个用户提供了一个令牌.您似乎希望在应用程序中获得更多细粒度,甚至可以根据登录令牌访问特定的资源.您对访问控制列表的想法是绝对正确的,是的,您已经发现了一个黑暗的秘密:没有人真正发布过如何设计或编写ACL机制.也就是说,它已经完成了.

首先,您熟悉unix文件权限吗?这是-rwxr-xr-x你在ls -l命令行中看到的东西.Unix选择了一种非常简化的ACL方法.每个登录的人都有一个用户ID(UID)和一个或多个组ID(GID)(whoami,groups).UNIX文件权限允许三种操作,Read,Write,并且Execute可以打开或关闭.在2 ^^ 9个状态下,这些权限很容易适合整数,然后Unix可以直接在文件系统中将该整数附加到文件中.当用户尝试访问文件时,权限将从严格到允许进行比较,匹配允许的最宽松权限.因此,用户获得第一组权限,组获得第二组,任何人获得第三组权限.因此,可执行文件通常是755:只有所有者可以更改它,但任何人都可以阅读和使用它.

其次,LDAP是轻量级目录访问协议,旨在为多个网络用户提供对资源的访问.OpenLDAP是一种常见的Linux实现,而Windows Server上的Microsoft的Active Directory会说LDAP(有很多扩展).LDAP具有更强大的ACL系统.一般配置是access to [resources] by [who] [type of access granted] [control]access to dn="uid=matt,ou=Users,dc=example,dc=com" by * none限制对Matt用户信息的所有访问.对于更完整的讨论,我强烈建议掌握LDAP,特别是关于安全性的第4章.(这是我从我的直接知识中得到的一点.)我的印象是LDAP将这些信息存储在一个单独的数据库表中,但我不知道这一点,也无法以这种或那种方式找到文档.我正在密切关注可能的架构.

简短总结:ACL采用用户令牌的概念,其中包含用户级别以上的可能组,以某种方式保护的对象集合,以及对这些部分的三个一致可能的操作 - 信息的3个维度.Unix存储其中两个维度,直接保护它们.OpenLDAP分别存储这三个维度,我们不太了解,但我怀疑是一个链接的树结构.

鉴于此,我们来看看如何为RESTful Web应用程序设计ACL系统.对于假设,我们将您的应用程序分解为离散的可寻址单元 - 每个需要保护的东西都可以通过URI(http://example.com/users,http://example.com/page_pieces/ticker)访问.我们的用户将是一个简单的UID/GID令牌 - 用户可以成为多个群组的一部分.最后,我们的可用操作将基于HTTP请求-GET,POST,PUT,DELETE等.我们现在需要一个能够有效处理三维数据数组的系统.我们的架构应该非常明显:(uri, userid, groupid, operations).我们故意将operations列反规范化为字符串列表,GET,POST,...因此我们只需要一个表.没有主键,因为我们永远不会真正按ID查找.

查询将分两步完成:SELECT * FROM acl WHERE uri=@uri, userid=@userid将返回0或1行.如果它返回1行,我们就完成了并且可以grep permisssion查看操作是否在列表中(使用*表示所有的perms).如果我们得到0行,则运行第二个查询SELECT * FROM acl WHERE uri=@uri, userid='*', groupid in (@groupid),该查询将再次返回0或某些行.如果它返回一些,循环并查看perms.如果它返回0,则执行最后一次查询SELECT * FROM acl WHERE uri=@uri, userid='*', groupid='*',最后返回0或1行.如果它返回1,请查看perms.如果返回0,则采取默认操作.

我们可以通过多种方式设置权限:

  • INSERT INTO acl VALUES (@uri, @userid, '', 'GET,POST') 允许单个用户GET或POST访问
  • INSERT INTO acl VALUES (@uri, '*', 'admin,contributors', 'GET,PUT,POST,DELETE')
  • INSERT INTO acl VALUES (@uri, '*', '*', '') 否认所有访问权限.

有几点需要注意:

  1. 必须准确表达所有URI; 此解决方案无法将默认权限设置为更高级别并让它们逐渐减少(作为练习器留给提问者).

  2. uri/uid/gid对的唯一性应该在某个时刻发生.应用程序可以处理它,或者在MySQL中可以执行ALTER TABLE acl ADD UNIQUE INDEX (uri, userid, groupid)(查找其他DBMS中类似约束的文档).