基于二进制位运算的权限控制
本文主要介绍如何基于二进制位运算(2的幂指数)实现精细化权限控制,将多个具体权限排列组合成一个整体权限进行使用。
Linux文件权限控制
在Linux中,通过chmod命令修改文件或目录的操作权限是经常用到的功能操作,例如
chmod 666 xxx (每个人都有读和写的权限)
chmod 777 xxx (每个人都有读和写以及执行的权限)
这里的数字777或666的每一位分别代表一种用户类型(文件所有者、群组用户、其他用户)的操作权限。 (如果感兴趣,可以深入研究下Linux的相关知识.)
单个6或7是怎么来的,代表什么意义呢?
实际上这里的6/7是三种具体的权限计算(相加)得出的权限组合值,文件或目录的具体权限分为3种:只读、只写、可执行
权限 | 权限数值 | 二进制 | 具体作用 |
---|---|---|---|
r | 4 | 00000100 | read,读取。当前用户可以读取文件内容,当前用户可以浏览目录 |
w | 2 | 00000010 | write,写入。当前用户可以新增或修改文件内容,当前用户可以删除、移动目录或目录内文件 |
x | 1 | 00000001 | execute,执行。当前用户可以执行文件,当前用户可以进入目录 |
依照上面的表格,权限组合就是对应权限值求和,如下:
7 = 4 + 2 + 1 读/写/运行权限
6 = 4 + 2 读/写权限
5 = 4 + 1 读/运行权限
4 = 4 只读权限
这样大家就明白666/777这些数字的意义了,实际上是通过组合得到的值。那为什么权限数值用的是1/2/4,而不是其他数字呢?
实现原理
首先看下为什么权限数值是1/2/4这样有规律的数值,而不是其他的数值?
其实,这里用的数值实际上是二进制,而1/2/4只是二进制转化为十进制后的结果。
int('00000001',2) = 1 # 2^0 执行
int('00000010',2) = 2 # 2^1 写
int('00000100',2) = 4 # 2^2 读
对比二进制就好理解了,其实是每一个标志位代表了一个权限,如果有权限对应位就是1,否则就是0。
7 = int('00000111',2) # 有3个标志位的权限 读+写+执行
如果想要检查权限组合值是否具有某个具体权限,可以通过二进制的位运算&进行判断。
相同位的两个数字都为1,则为1;若有一个不为1,则为0
7: 0 0 0 0 0 1 1 1
2: 0 0 0 0 0 0 1 0
————————————————————
2: 0 0 0 0 0 0 1 0
7&1 = 1
7&2 = 2
7&4 = 4
这样我们就明白了使用2的幂指数(1/2/4/8/16/...)进行权限控制的原理,实际上是通过二进制的标志位进行的控制。
应用权限控制
在应用系统中,权限控制是最基本的功能,对于资源的访问一般都要进行权限(增/删/改/查)控制,可以将一个角色的各种权限用多条记录分别记录下来,不过稍显繁琐, 那我们是不是也可以借鉴Linux的实现方式,通过类似数字组合的方式进行权限控制呢?
接下来我们通过一个基于角色的权限控制应用案例,看一下实现思路(以下代码基于Python+SQLAlchemy)
# 操作权限类型常量
class Permission:
ADD = 1 # 2^0
DELETE = 2 # 2^1
UPDATE = 4 # 2^2
QUERY = 8 # 2^3
# 角色
class Role(Base):
__tablename__ = 'sys_roles'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(32), unique=True, nullable=False)
permissions = Column(Integer, nullable=False)
def add_permission(self, permission):
if not self.has_permission(permission):
self.permissions += permission
def remove_permission(self, permission):
if self.has_permission(permission):
self.permissions -= permission
def reset_permission(self):
self.permissions = 0
def has_permission(self, permission):
return self.permissions & permission == permission # 位运算,判断是否有权限
# 用户,权限由其对应的角色进行控制
class User(Base, ModelMixin):
# ...
role_id = Column(Integer, ForeignKey('sys_roles.id'), nullable=False)
role = relationship('Role')
def can(self, permission):
return self.role is not None and self.role.has_permission(permission)
#以下为测试代码
>>> role = Role()
>>> role.add_permission(Permission.ADD)
>>> role.add_permission(Permission.QUERY)
>>> role.has_permission(Permission.QUERY) # True
>>> user = User()
>>> user.role = role
>>> user.can(Permission.QUERY) # True
>>> user.can(Permission.DELETE) # False
这样我们就基于二进制运算实现了权限控制,不过具体的应用会更复杂,可能还会包括菜单权限等,但是实现思路大致相同。