前言
本文章是对我之前一篇有关Linux操作系统通过二进制实现用户权限控制原理的java代码实现上扩充。
一是为了巩固知识点,另一方面是想让那一篇的理论知识落到实处。项目源码会在文章中放出。
注意:实现并不是完全按照Linux的模型进行实现,主要是让大家明白二进制的运算在本例的作用。
一、模拟环境及需求
1. 开发环境
- IDEA 2019.1.4
- JDK1.8
- maven
pom.xml的jar包依赖(没有给出指定版本) <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies>
2. 功能需求
- 两个实体:用户、文件、权限。权限只有三种:读、写、可执行。文件和用户都具有权限,但只有两者的权限匹配的时候才能实现操作。
- 原理链接:二进制的妙用——通过二进制解决权限控制(Linux)
二、实现步骤
1.创建实体
// user实体
@AllArgsConstructor
@Setter
@Getter
public class User {
private String name;
/**
* 默认权限全空
*/
private Integer auth = 0B000;
@Override
public String toString() {
return name + "拥有" + AuthTools.authTools.pintf(this.auth);
}
}
// file实体
@AllArgsConstructor
@Setter
@Getter
public class File {
private String name;
/**
* 默认权限全空
*/
private Integer auth = 0B000;
@Override
public String toString() {
return name+"拥有"+ AuthTools.authTools.pintf(this.auth);
}
}
// 操作枚举
@AllArgsConstructor
@Getter
public enum Authority {
/**
* 读权限 0B100 = 4
*/
READABLE(0B100, "可读"),
/**
* 读权限 0B010 = 2
*/
WRITABLE(0B010, "可写"),
/**
* 读权限 0B001 = 1
*/
RUNNABLE(0B001, "可运行");
private Integer value;
private String name;
}
2.编写逻辑
public class AuthTools {
public static AuthTools authTools = new AuthTools();
/**
* Description:
* 给user 添加 authoritys 的权限
*
* @param user:
* @param authoritys:
* @date 2020/12/13 10:11
**/
public void addUserAuth(User user, Authority... authoritys) {
user.setAuth(this.addAuth(user.getAuth(), authoritys));
}
/**
* Description:
* 给user 删除 authoritys 的权限
*
* @param user:
* @param authoritys:
* @date 2020/12/13 10:11
**/
public void delUserAuth(User user, Authority... authoritys) {
user.setAuth(this.delAuth(user.getAuth(), authoritys));
}
/**
* Description:
* 给file 添加 authoritys 的权限
*
* @param file:
* @param authoritys:
* @date 2020/12/13 10:11
**/
public void addFileAuth(File file, Authority... authoritys) {
file.setAuth(this.addAuth(file.getAuth(), authoritys));
}
/**
* Description:
* 给file 删除 authoritys 的权限
*
* @param file:
* @param authoritys:
* @date 2020/12/13 10:11
**/
public void delFileAuth(File file, Authority... authoritys) {
file.setAuth(this.delAuth(file.getAuth(), authoritys));
}
/**
* Description:
* user对file执行operation操作
*
* @param user:
* @param file:
* @param operation:
* @date 2020/12/13 10:11
**/
public void execOpera(User user, File file, Authority operation) {
// 执行操作主程序
// 执行判断逻辑,只有user和file都有operation的权限的时候才可以执行
// 比如 user:0B101 file:0B110 operation:0B100 就可以
// 比如 user:0B001 file:0B110 operation:0B100 不可以 user用户本身就没有读权限
// 细粒度分析:只要对应位置的二进制都是1就为true,否则为false
if (this.judgeOperation(user.getAuth(), operation) &&
this.judgeOperation(file.getAuth(), operation)) {
System.out.println(user.getName() + "进行" + operation.getName() + "操作成功");
} else {
System.out.println(user.getName() + "进行" + operation.getName() + "操作失败");
}
}
private Integer addAuth(Integer integer, Authority... authorities) {
// 添加权限主程序
// 获取本次操作的实际权限集合
Integer mergeAuth = mergeAuth(authorities);
// 返回二者的合并即可
return integer | mergeAuth;
}
private Integer delAuth(Integer integer, Authority... authorities) {
// 删除权限主程序
// 获取本次操作的实际权限集合
Integer mergeAuth = mergeAuth(authorities);
// 返回二者的差
// 例子:user的权限0B110(读写权限)删除0B011(执行与写权限),结果为0B100(读权限)
// 细粒度分析:0+0= 0,1+0 = 1, 0+1=0,1+1=0 (+代表位运算符号可能是| 也可能是 & 也可能是组合的)
integer = ~(~integer | mergeAuth);
return integer;
}
/**
* Description:
* 用于计算出本次操作总权限是什么
*
* @param authorities: 权限集合
* @return java.lang.Integer: 合并总权限
* @date 2020/12/13 10:27
**/
private Integer mergeAuth(Authority... authorities) {
Integer auth = 0B000;
for (Authority authority : authorities) {
// 二进制位与操作
// 解析:此处是合并操作,说明是要从 0 -> 1的变化
// 例子:0B000(空权限) + 0B100(读权限) = 0B100(读权限)
// 位运算细粒度分析: 0+1=1、0+0=0、1+0=1,1+1=1。(+代表位运算符号可能是| 也可能是 & 也可能是组合的)
auth = auth | authority.getValue();
}
return auth;
}
private Boolean judgeOperation(Integer auth, Authority authority) {
// 细粒度分析 0+0=0, 0+1=0, 1+0=0, 1+1=1
return (auth & authority.getValue()) == authority.getValue();
}
/**
* Description:
* 打印interger所拥有的权限
*
* @param integer:
* @return java.lang.String
* @date 2020/12/13 11:20
**/
public String pintf(Integer integer) {
String str = "【";
if (this.judgeOperation(integer, Authority.READABLE)) {
str += Authority.READABLE.getName();
}
if (this.judgeOperation(integer, Authority.WRITABLE)) {
str += "、" + Authority.WRITABLE.getName();
}
if (this.judgeOperation(integer, Authority.RUNNABLE)) {
str += "、" + Authority.RUNNABLE.getName();
}
return str + "】";
}
}
3.编写测试环境
public class Run {
/*
默认创建一个文件和两个用户,并且将他们的权限默认为全空
*/
private File file = new File("系统文件.txt", 0B000);
private User user1 = new User("用户一", 0B000);
private User user2 = new User("用户二", 0B000);
private AuthTools authTools = AuthTools.authTools;
/**
* 给user1赋予Read权限
*/
@Test
public void addUser1Read() {
System.out.println("赋值前:" + user1);
authTools.addUserAuth(user1, Authority.READABLE);
System.out.println("赋值后:" + user1);
}
/**
* 给user2赋予Write和Runnable权限
*/
@Test
public void addUser2Write() {
System.out.println("赋值前:" + user2);
authTools.addUserAuth(user2, Authority.WRITABLE, Authority.RUNNABLE);
System.out.println("赋值后:" + user2);
}
/**
* 删除use1的可运行权限
*/
@Test
public void delUser1Write() {
// 先给予全部权限
authTools.addUserAuth(user1, Authority.READABLE, Authority.WRITABLE, Authority.RUNNABLE);
System.out.println("user1:" + user1);
authTools.delUserAuth(user1, Authority.RUNNABLE);
System.out.println("删除可运行权限后user1:" + user1);
}
/**
* 测试file的运行的情况
*/
@Test
public void execFileByUser() {
authTools.addFileAuth(file, Authority.RUNNABLE, Authority.READABLE);
System.out.println("file:" + file);
authTools.addUserAuth(user1, Authority.READABLE);
System.out.println("user1:"+user1);
System.out.println("user2:"+user2);
authTools.execOpera(user1, file, Authority.READABLE);
authTools.execOpera(user1, file, Authority.RUNNABLE);
authTools.execOpera(user2, file, Authority.READABLE);
}
}
4.代码结构
--com
-- binary
--entity
-- enum Authority (操作枚举)
-- class File (文件)
-- class User (用户)
--test
-- class Run (测试类)
--tool
-- class AuthTools (权限控制类)
总结
通过本次代码测验主要是回归二进制的用法之一。
经过本测验,我们其实在个人的学习上使用这种方式去进行动态的业务属性增添,比如说权限、电影与种类的对应。在经过统一和确定的情况下,这种方式不失为一种快捷方式,还减少了存储空间。
当然其弊端
也是很大的,所以大家也可以将此文章作为二进制运算
的练习。
通过明白二进制的各种运算,我们的思维会更加贴合计算机本身,更好地巩固我们的内功。