# lotus **Repository Path**: clouddea/lotus ## Basic Information - **Project Name**: lotus - **Description**: 莲花,一个基于微服务的后端程序。您只需要设计Mysql数据库,即可自动生成符合Restful范式的后端接口。并且不用担心接口的安全问题,因为它可以自动生成符合RBAC(Role Based Access Control)权限控制模型的数据表结构,每一个接口都将验证权限。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2021-01-28 - **Last Updated**: 2022-09-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 简介 只需要配置数据库,一个后端程序就起来了,是不是很酷? 是的,Lotus就是为了减少后端工作量而生的! 她不仅支持难搞的**权限控制**,还支持`分布式部署`以及`负载均衡`。只需要 `java -jar xxxx ` 一条命令,就可以生成全业务支持的Restful API! 欢迎反馈Bug~ # 使用 直接下载jar文件,即可运行。 下载地址: [https://gitee.com/clouddea/lotus/releases](https://gitee.com/clouddea/lotus/releases) ## 程序运行 运行环镜要求: + JRE 11+ + MySQL 5.7 以上 + Redis [可选] 3.2.100 运行命令格式 ```shell 输入格式: 本程序 [-H] [-M=] [-U] [-P=] 选项解释: -H - 打印帮助 -M - 指定mysql, 默认是localhost:3306/lotus/lotus/lotus -U - 指明创建用户权限信息,启上此项后,会在数据库中自动创建符合RBAC的权限表,并且系统程序支持使用 /login 进行登录 -P= - 指定程序运行的端口号,默认为8080 参数解释: port - 运行的端口号,例如 8080 mysql - 例如 127.0.0.2:8080/dbPath/dbUser/dbPass ``` ## 数据库配置 由于权限控制需要,对数据库的数据表有一些限制要求。当且仅当满足全部要求时,该数据表才能被程序识别。 + 存在字段`id`,类型为int或bigint,自增,表示数据的主键 + 存在字段`create_id`,类型为int或bigint,表示数据的创建者 + 存在字段`update_id`,类型为int或bigint,表示数据的更新者 + 存在字段`object_role`,类型为int或bigint,表示数据的拥有角色, 当object_role = 0 时将只有创建者拥有操作权限 您不需要建立用户表、角色表等与权限控制相关的表。因为当您指定 **-U** 参数时,程序全自动生成相关表结构。您可在此基础上添加需要的字段。 自动生成的表包括: + _user 表示用户表 + _role 表示角色表 + _tran 表示权限表 + _role_tran 角色权限表 + _user_role 用户角色表 您虽然不需要手动创建这些表,但是您需要为这些表`添加数据`,从而构建出系统的权限结构。 以下是一个自定义表的示例: ![image-20210718132329693](doc/image-20210718132329693.png) 在程序启动时,则可以自动识别该表了: ![image-20210718132553829](doc/image-20210718132553829.png) ### _user 表 该表存在系统中存在的用户。 id account 用户的账号 password 用户的密码 create_id update_id object_role phone 用户的手机号 email 用户的邮箱号码 ### _role 表 该表存储系统中存在的角色 id name 角色名称 parent_id 角色的上级角色。角色会链式地继承所有上级角色的权限。 create_id update_id object_role ### _tran 表 该表存储系统中存在的权限 id object_name 对象名。即表名称,需与创建表时的名称完全一致。 operation 操作名称。即定义表的一些操作。 create_id update_id object_role [操作名称]: 程序一共可以识别 13种操作名称: ``` insert 对某个表创建记录 deleteAll 删除某个表任意一条记录 delete 删除某个表用户自己创建的记录 deleteGroup 删除某个表用户自己或组内其它人所创建的记录 (这里的组,即角色,下同) updateAll 更新某个表任意一条记录 update 更新某个表用户自己创建的记录 updateGroup 更新某个表用户自己或组内其它成员创建的记录 adminAll 更新某个表任意一条记录的保护字段 admin 更新某个表用户自己创建的记录的保护字段 adminGroup 更新某个表用户自己或组内其它成员创建的记录的保护字段 selectAll select selectGroup ``` 其中,更新保护字段是指对 `id`, `createId`, `updateId`,`objectRole`这四个字段的更新。 ### _user_role表 该表管理用户所属的角色 id user_id 用户的id role_id 角色的id create_id update_id object_role ### _role_tran表 该表管理角色可以操作的权限 id role_id 角色的id tran_id 权限的id create_id update_id object_role ### 配置示例 假设系统中有`游客`和`系统管理员`两种角色。我们基于此开发一个私有博客系统。显然,需要一张数据表来存储博客内容,假定为`article`。 (1)首先在_role表中创建这两种角色: 游客(匿名)可以读系统中所有文章,而超级管理员也可以读文章,所以直接让超级管理员这个角色继承游客角色。即设置parent_id = 1 指向匿名角色的id。 ![image-20210718142631869](doc/image-20210718142631869.png) (2)然后在_role表中创建两个角色的两个用户: ![image-20210718142705459](doc/image-20210718142705459.png) (3)再在_tran表中配置系统中所有的操作权限: 这里我们只选择了insert、updateAll、updateAll、selectAll四种。 ![image-20210718142753486](doc/image-20210718142753486.png) (4)在_user_role中配置用户对应角色 配置`anonymouse`用户为匿名角色 配置`管理员A`用户为超级管理员角色 ![image-20210718143453350](doc/image-20210718143453350.png) (5)最后在_role_tran中配置角色的权限 配置匿名角色可以对article进行selectAll, 配置超级管理员角色可以对article进行insert、updateAll、updateAll。 因为超级管理员继承了匿名角色,所以不用单独配置selectAll了。 ![image-20210718143634656](doc/image-20210718143634656.png) 配置好后重新启用程序即可。 ## API 访问规则 当数据库配置完成并启动程序后。可通过Restful API对数据资源进行操作。 #### 登录 必须要登录之后才能进行后续所有操作。返回的结果中包含其它接口使用的`token`。匿名用户也需要登录。 ``` 访问方式:POST 访问路径: http://{ip}:{port}/ 参数类型:query或x-www-form-urlencoded 返回值示例: { "code": 0, "message": "操作成功", "data": "eyJhbGciOiJFUzI1NiJ9.eyJqdGkiOiIyIiwicm9sZXMiOlsiMSIsIjIiXSwicGVybXMiOlsiYXJ0aWNsZV91cGRhdGVBbGwiLCJhcnRpY2xlX2RlbGV0ZUFsbCIsImFydGljbGVfaW5zZXJ0IiwiYXJ0aWNsZV9zZWxlY3RBbGwiXSwiZXhwIjoxNjI2NTkwNjI4fQ.AXiY1U5K8r_aMKkA2OitYFpfJr8G7quXSKaX1hOhJhu6SBQ695CpQjCFPlpWw6OM3V0ecsCzLdvb9ZShWoygLQ" } ``` | 参数名 | 参数值 | 备注 | | -------- | ------ | -------------- | | action | login | 动作 | | expire | | 登录过期毫秒数 | | account | | 账号 | | password | | 密码 | ### 增加数据 ``` 访问方式:POST 访问路径: http://{ip}:{port}/{表名} 参数类型:query或x-www-form-urlencoded 返回值示例: { "code": 0, "message": "操作成功", "data": "2" } 返回值data 表示刚刚增加的id ``` | 参数名 | 参数值 | 备注 | | ------ | ------- | ------------------------------ | | token | | 令牌 | | {key} | {value} | 创建的时间指定的默认属性和值。 | 其中key和value可以设置多个 ### 更新数据 ``` 访问方式:PUT 访问路径: http://{ip}:{port}/{表名}/{记录的id} 参数类型:query或x-www-form-urlencoded 返回值示例: { "code": 0, "message": "操作成功" } ``` | 参数名 | 参数值 | 备注 | | ------ | ------- | ---------------- | | token | | 令牌 | | {key} | {value} | 要更新的字段和值 | 其中key和value可以设置多个 ### 删除数据 ``` 访问方式:DELETE 访问路径: http://{ip}:{port}/{表名}/{记录的id} 返回值示例: { "code": 0, "message": "操作成功" } ``` | 参数名 | 参数值 | 备注 | | ------ | ------ | ---- | | token | | 令牌 | ### 查询数据 必须要登录之后才能进行后续所有操作。返回的结果中包含其它接口使用的`token`。匿名用户也需要登录。 ``` 访问方式:GET 访问路径: http://{ip}:{port}/{表名} 参数类型:query或x-www-form-urlencoded 返回值示例1: { "code": 0, "message": "操作成功", "data": 2 } 返回值示例2: { "code": 0, "message": "操作成功", "data": [ { "update_id": "2", "update_time": "1626592870000", "create_id": "2", "create_time": "1626592870000", "object_role": "0", "id": "2", "title": "震惊!实验竟然成功了", "content": "文章内容2" }, { "update_id": "2", "update_time": "1626589221000", "create_id": "2", "create_time": "1626589221000", "object_role": "0", "id": "1", "title": "这是一篇文章", "content": "文章内容" } ] } ``` | 参数名 | 类型 | 参数值 | 备注 | | ----------------- | ------ | ------- | ------------------------------------ | | token | 字符串 | | 动作 | | count | 数字 | | 取值为“0”或“1”,表示是否仅仅返回计数 | | offset | 数字 | | 从哪里开始获取 | | limit | 数字 | | 限制最大返回个数 | | {key} | 字符串 | {value} | 字符串模糊或数字精确查找。 | | {key}.{operation} | 字符串 | {value} | 查询条件 | | {key}.{order} | 字符串 | {value} | 排序条件 | 其中 + key 表示字段名 + operation 取值为 `eq` 、`neq`、 `gt`、 `ge`、 `lt`、 `le` 分别表示 等于、不等于、大于、大于等于、小于、小于等于 比较条件。 + order 取值为 `asc` 、`desc` 分别表示正向和负向排序 注意: + 当count=1时,只会返回个数。此时 排序条件、offset、limit将无效。 + 当count=0时,返回实际数据,但是没有权限的数据将会被过滤掉。 + 如果要使用模糊查找,请在value中添加 `%`或`_`。即MySQL模糊查找的通配规则。 ### 查询一条数据 查询一条记录的详细信息 ``` 访问方式:GET 访问路径: http://{ip}:{port}/{表名}/{记录的id} 参数类型:query或x-www-form-urlencoded 返回值示例1: { "code": 0, "message": "操作成功", "data": { "update_id": "2", "update_time": "1626589221000", "create_id": "2", "create_time": "1626589221000", "object_role": "0", "id": "1", "title": "这是一篇文章", "content": "文章内容" } } ``` | 参数名 | 参数值 | 备注 | | ------ | ------ | ---- | | token | | 令牌 | # 开发 支持用户在源码基础上增强其它功能。 开发环镜: + JDK 11+ + MySQL + Redis [可选] 其中,数据库是可更换的,实现其中的`DAO`接口即可。如果不想用服务注册发现功能,Redis也是可选的。 源码**非常简单**,阅读即可。 ## TODOs - [√] 完善单元测试 - [ ] 将目前的RBAC权限模型进行增强 - [√] 把角色权限的继承关系替换为组合关系 - [√] 支持自定义权限和扩展API - [ ] 考虑更换为ABAC权限模型 - [ ] 增强配置性 - [ ] 开发权限配置小工具(桌面GUI程序) - [ ] 目前select操作是返回所有字段,之后会限制select的返回字段。 - [ ] 实现一致性协议组建服务集群 - Primary-backup Protocols + 选举算法 (一种思路,暂不考虑实现 ) - 或者 Client-centric Protocols - 或者 Gossip协议 ## Notes 本程序不再考虑支持分库分表情况,因为这种架构已经有了更好的替代方案:分片代理(如ShadingSphere)、分布式数据库(如GaussDB) 本程序不考虑使用MD5对密码进行digest,因为使用Nginx代理并配置HTTPS后,可以安全地传输明文密码