{"id":15435343,"url":"https://github.com/guotie/acl","last_synced_at":"2025-08-18T19:34:45.846Z","repository":{"id":147641711,"uuid":"86690506","full_name":"guotie/acl","owner":"guotie","description":"acl based permission","archived":false,"fork":false,"pushed_at":"2017-04-01T00:51:34.000Z","size":36,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-18T09:30:57.121Z","etag":null,"topics":["acl","authorization","go","permission","rbac"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guotie.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-30T10:32:25.000Z","updated_at":"2017-04-01T01:04:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"41702f1f-49b2-44bd-87a8-664659e15b8b","html_url":"https://github.com/guotie/acl","commit_stats":{"total_commits":11,"total_committers":1,"mean_commits":11.0,"dds":0.0,"last_synced_commit":"c069c822377ff03ce6f8a6e0680917a131b79e70"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guotie%2Facl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guotie%2Facl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guotie%2Facl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guotie%2Facl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guotie","download_url":"https://codeload.github.com/guotie/acl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245978277,"owners_count":20703678,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acl","authorization","go","permission","rbac"],"created_at":"2024-10-01T18:43:40.027Z","updated_at":"2025-03-28T06:14:03.170Z","avatar_url":"https://github.com/guotie.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ACL access control list\r\n\r\n参考借鉴 shiro和spring security的权限管理, 100% 测试覆盖\r\n\r\n# 名词概念\r\n\r\n## ACL\r\n访问控制列表。\r\n\r\n## Rule\r\n权限判断辅助规则, 目前需要硬编码。\r\n\r\n在有些时候，ACL判断规则会比较繁琐，例如：\r\n\r\n在分级权限管理中，假如分为四级：总部级，省级，市级，县级。\r\n省级管理人员可以管理下面所有市级、县级的营业厅，市级管理人员可以管理所有的本市的营业厅和下面县的营业厅，A市共有100家营业厅。\r\n\r\n如果按照ACL的规则，则需要给省级管理人员配置所有营业厅的管理权限，就是需要N条记录。而且，每增加、删除营业厅，都需要重新修改权限\r\n的ACL规则。\r\n\r\n按照rule的配置规则，则仅仅需要编写一个函数，判断省级的管理人员是否有该营业厅的权限即可。\r\n\r\n当然，rule函数规则和业务关联紧密，需要在代码中写死，灵活性欠缺。\r\n\r\n## Principal\r\n\r\n一个接口，特指Account或者Role\r\n\r\n\r\n# 用法说明\r\n\r\n## 权限主体 Account\r\n\r\n你需要自己定义Account Model，并为Account实现 Principal 接口的两个方法：\r\n\r\n```\r\ntype AclObject interface {\r\n\tGetSid() string // 通常是 uuid\r\n\tGetTyp() string // object类型, user, role, post, etc...\r\n}\r\n\r\ntype Principal interface {\r\n\tAclObject\r\n}\r\n\r\n```\r\n\r\nAccount 的 GetSid方法返回Account的Sid，通常为UUID\r\nAccount 的 GetTyp方法返回 _*acl.AccountTyp*_, 为\"AccountTyp\"\r\n\r\n## 权限标的\r\n\r\nAccount 要操作的权限标的必须实现 AclObject 接口.\r\n\r\n权限标的 GetTyp 方法返回权限标的 类型。\r\n\r\n## 角色Role\r\n\r\n角色最重要的两个接口：\r\n\r\n1. 创建角色\r\n```\r\nfunc (mgr *AclManager) CreateRole(name, sid, depart, corp, city, province string, level int) (*Role, error) {\r\n```\r\n- name:     角色名称\r\n- sid:      角色全局id, 通常为空, 由uuid自动生成\r\n- depart:   角色所在部门\r\n- corp:     角色所在公司\r\n- city:     角色所在城市\r\n- province: 角色所在省份\r\n- level:    角色级别\r\n\r\n2. 将Account加入到角色中：\r\n```\r\nfunc (mgr *AclManager) AddUserRoleRelation(uid, rid string) error\r\n```\r\n- uid: Account的uuid\r\n- rid: role的uuid\r\n\r\n## Permission\r\n\r\nPermission 比较简单, 核心是一个类型为uint32, 名为Mask的字段。 通过 请求的操作权限 与 AclEntry 中的权限做 \u0026 操作, 来决定是否具备操作权限\r\n\r\nMask每一位代表一种权限，目前已定义的权限如下：\r\n```\r\n\tPermissionRead   = 1 \u003c\u003c permIndexRead   // 读权限\r\n\tPermissionWrite  = 1 \u003c\u003c permIndexWrite  // 写权限\r\n\tPermissionCreate = 1 \u003c\u003c permIndexCreate // 创建权限\r\n\tPermissionDelete = 1 \u003c\u003c permIndexDelete // 删除权限\r\n\tPermissionManage = 1 \u003c\u003c permIndexManage // 管理权限\r\n```\r\n\r\n## 权限访问控制列表 AclEntry\r\n\r\n通过AclEntry来控制一个账号或一个角色是否对权限标的有特定的权限\r\n\r\n创建ACL entry：\r\n```\r\nfunc (mgr *AclManager) CreateACE(whoSid, whoTyp, whatSid, whatTyp    string, mask uint32, order int,\r\n\tgrant, auditSuccess, auditFailure bool) (*AclEntry, error)\r\n```\r\n\r\n- whoSid:      权限主体sid\r\n- whoTyp:      权限主体类型, 通常为AccountTyp或RoleTyp\r\n- whatSid:     权限标的sid\r\n- whatTyp:     权限标的类型\r\n- mask:        权限\r\n- order:       创建的Acl在Acl list的顺序, 判断权限时, AclEntry安装order从小到大逐条判定\r\n- grant:       授权或拒绝\r\n- auditSuccess: 当授权时, 是否审计\r\n- auditFailure: 当拒绝时, 是否审计\r\n\r\n## AclManager\r\n```\r\nfunc CreateAclManager(db *gorm.DB, pool *redis.Pool) *AclManager \r\n```\r\nCreateAclManager 用来创建 AclManager 对象\r\n\r\n在上面的工作都准备好以后，就可以通过IsGrant接口来查询权限：\r\n```\r\nfunc (mgr *AclManager) IsGrant(who AclObject, what AclObject, perm Permission) bool {\r\n```\r\n- who:  权限主体, 可以是Account，也可以是Role\r\n- what: 权限标的\r\n- perm: 请求的权限\r\n- 返回： true: 授权 false：拒绝\r\n\r\n\r\n# 权限判断流程\r\n\r\n权限判断通过这个接口来查询:\r\n\r\n```\r\nfunc (mgr *AclManager) IsGrant(who AclObject, what AclObject, perm Permission) bool\r\n```\r\n\r\n流程：\r\n\r\n0. 首先，根据who查找who的principls, 即who本身和who所属的roles;\r\n\r\n1. 对于who所属的每个principal: \r\n\r\n    a. 查找who关联的rules, 轮询每条rule, 该rule 是否能够判定权限, 如果该rule判定出权限(Grant或Reject), 返回权限; 否则, 返回0;\r\n\r\n    b. 查找who关联所有 acl, 轮询每条acl, 该acl 是否能够判定权限, 如果能判定出权限(Grant或Reject), 返回权限; 否则, 返回0;\r\n\r\n2. 如果以上步骤未判定出权限, 返回拒绝(Reject)\r\n\r\n\r\n## 缓存\r\n\r\n查询权限时，优先从缓存中查找。\r\n\r\n缓存使用redis保存，主要有以下2种：\r\n\r\n1. user对应的角色列表, 使用 redis set 保存; \r\n2. principal 对应的 acl 列表, 使用 redis hashmap 保存；\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguotie%2Facl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguotie%2Facl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguotie%2Facl/lists"}