{"id":31535908,"url":"https://github.com/solonlab/grit","last_synced_at":"2025-10-28T11:06:25.442Z","repository":{"id":41408547,"uuid":"390578024","full_name":"solonlab/grit","owner":"solonlab","description":"资源授权管理中心（中间件）","archived":false,"fork":false,"pushed_at":"2025-10-01T16:50:49.000Z","size":2415,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-01T16:53:51.741Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solonlab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2021-07-29T02:42:58.000Z","updated_at":"2025-10-01T16:50:53.000Z","dependencies_parsed_at":"2023-02-09T12:31:38.441Z","dependency_job_id":"b1a79b25-7ffe-48c8-9e8f-5cb36be3b0f7","html_url":"https://github.com/solonlab/grit","commit_stats":null,"previous_names":["solonlab/grit","noear/grit"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/solonlab/grit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solonlab%2Fgrit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solonlab%2Fgrit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solonlab%2Fgrit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solonlab%2Fgrit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solonlab","download_url":"https://codeload.github.com/solonlab/grit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solonlab%2Fgrit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278273836,"owners_count":25959802,"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","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-10-04T06:20:08.526Z","updated_at":"2025-10-04T06:20:12.038Z","avatar_url":"https://github.com/solonlab.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\" style=\"text-align:center;\"\u003e\n  Grit\n\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n权限管理系统，或者资源授权管理中心，或者权限控制中台\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca target=\"_blank\" href=\"https://search.maven.org/search?q=org.noear%20grit\"\u003e\n        \u003cimg src=\"https://img.shields.io/maven-central/v/org.noear/grit-client.svg?label=Maven%20Central\" alt=\"Maven\" /\u003e\n    \u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"LICENSE\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/:license-AGPL3.0-blue.svg\" alt=\"AGPL3.0\" /\u003e\n\t\u003c/a\u003e\n    \u003ca target=\"_blank\" href=\"https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/badge/JDK-8+-green.svg\" alt=\"jdk-8+\" /\u003e\n\t\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003ca target=\"_blank\" href='https://gitee.com/noear/grit/stargazers'\u003e\n\t\t\u003cimg src='https://gitee.com/noear/grit/badge/star.svg' alt='gitee star'/\u003e\n\t\u003c/a\u003e\n    \u003ca target=\"_blank\" href='https://github.com/noear/grit/stargazers'\u003e\n\t\t\u003cimg src=\"https://img.shields.io/github/stars/noear/grit.svg?logo=github\" alt=\"github star\"/\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n\n## 功能\n\n* 资源管理\n  * 资源空间（相当于应用系统）\n  * 资源组（相当于频道、模块）\n  * 资源\n    * 可见（相当于菜单）\n    * 可不见（相当于权限码）\n* 主体管理\n  * 主体组\n    * 可见（相当于企业、机构、部门）\n    * 不可见（相当于角色）\n  * 主体（相当于登录用户）\n\n## 开始\n\n* 了解框架与构件\n\n| 开发框架                     | 说明                                   | \n|--------------------------|--------------------------------------| \n| grit-client              | grit 接口申明及数据实体定义。支持Remote调用与Local调用  | \n| grit-client-solon-solon  | grit-client 集成插件（带 solon-auth 适配）    | \n| grit-server-api          | grit-client 接口实现（可做为插件集成到别的服务）       | \n| grit-server-ui-durian    | grit-server + 管理界面实现（可做为插件集成到别的管理后台） | \n| grit-server-solon-solon  | grit-server 集成插件                     | \n\n\n| 镜像输出               | 说明                    | \n|--------------------|-----------------------| \n| noearorg/gritdock:2.1.0 | Grit 权限管理、接口服务及菜单导航服务 | \n\n\n单体项目，可通过 grit-server-ui-durian 集成，直接获取客户端接口与管理能力\n\n* 控制台演示站\n\n授权管理地址： [http://grit.noear.org/grit/](http://grit.noear.org/grit/)  （账号：grit ；密码：UjKeQwBK1oCUOCvl ）\n\n效果预览地址：[http://grit.noear.org/](http://grit.noear.org/)  （已有演示主体，账号：admin ；密码：admin ）\n\n\n* 部署说明\n\n具体参考：[_deploy](_deploy)\n\n\n* 管理说明\n\n上面的演示控制台，可以先上去看看。或者看视频：[https://www.bilibili.com/video/BV1Hy42187cn/](https://www.bilibili.com/video/BV1Hy42187cn/)\n\n## 应用\n\n### 配置应用\n\n#### 1、单体模式\n\n* 依赖包配置（pom.xml）\n\n```xml\n\u003cdependencies\u003e\n  \u003c!-- 引入 solon 的签权适配版本，方便做签权 --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003egrit-solon-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.0\u003c/version\u003e\n  \u003c/dependency\u003e\n  \n  \u003c!-- 单体自己就是 server（需要配置数据库连接） --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003egrit.server\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.0\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n* 应用属性配置（app.yml）//需要先初始化好数据库\n\n```yml\nsolon.app:\n  name: \"demoadmin\"\n  group: \"demo\"\n\ngrit.db:\n  schema: grit\n  server: grit.io:3306\n  username: demo\n  password: 123456\n```\n\n\n#### 2、分布式模式\n\n* 依赖包配置（pom.xml）\n\n```xml\n\u003cdependencies\u003e\n  \u003c!-- 引入 solon 的签权适配版本，方便做签权（server 由 rpc 提供） --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003egrit-solon-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.0\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n* 应用属性配置（app.yml）//直接申明服务地址\n\n```yml\nsolon.app:\n  name: \"demoadmin\"\n  group: \"demo\"\n\ngrit:\n  server: \"http://localhost:7281\"\n  token: \"B6uWZDYUm4kMscdEAERXQ2wMBW1nLL0j\"\n```\n\n\n\n#### 3、分布式模式（使用注册与发现服务）\n\n\n* 依赖包配置（pom.xml）\n\n```xml\n\u003cdependencies\u003e\n  \u003c!-- 引入 solon 的签权适配版本，方便做签权（server 由 rpc 提供） --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003egrit-solon-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.0\u003c/version\u003e\n  \u003c/dependency\u003e\n\n  \u003c!-- 引入 solon 的注册与发现组件（比如：water-solon-cloud-plugin） --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003ewater-solon-cloud-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e2.8.0\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n* 应用属性配置（app.yml）//从发现服务获取服务地址\n\n```yml\nsolon.app:\n  name: \"demoadmin\"\n  group: \"demo\"\n\nsolon.cloud.water:\n  server: \"waterapi:9371\"           #WATER服务地址\n\n#此内容可以放到配置服务里\ngrit:\n  server: \"@gritapi\"                #会借用发现服务获取集群节点\n  token: \"B6uWZDYUm4kMscdEAERXQ2wMBW1nLL0j\"\n```\n\n\n#### 4、其它模式\n\n略...\n\n### 代码应用\n\n```java\n//1，定义认证处理器\npublic class AuthProcessorImpl extends GritAuthProcessor {\n    \n}\n\n//2，配置验证规则\n@Configuration\npublic class DemoConfig{\n    @Bean\n    public void initAuth() {\n        //适配认证框架\n        AuthUtil.adapter()\n                .loginUrl(\"/login\")\n                .addRule(r -\u003e r.include(\"**\").verifyIp().failure((c, t) -\u003e c.output(c.realIp() + \", not whitelist\"))) //增加ip白名单验证规则\n                .addRule(r -\u003e r.exclude(\"/login**\").exclude(HealthHandler.HANDLER_PATH).exclude(\"/_**\").verifyPath()) //增加uri验证规则\n                .processor(new AuthProcessorImpl()) //绑定验证处理器\n                .failure((ctx, rst) -\u003e {\n                    ctx.render(Result.failure(403,\"你，没有权限哟!\"));\n                });\n    }\n}\n\n//3，登录示例\n@Controller\npublic class LoginController{\n    @Mapping(\"/login\")\n    public Result login(String userName, String userPassword){\n        //尝试登录\n        Subject subject = GritClient.global().auth().login(userName, userPassword);\n\n        if (Subject.isEmpty(subject)) {\n            return Result.failure(\"提示：账号或密码不对！\");\n        } else {\n            //加载用户主体信息到会话状态\n            Session.current().loadSubject(subject);\n            \n            //找到用户有权限的一个可见uri\n            Resource res = GritClient.global().auth().getUriFrist(subject.subject_id);\n\n            if (Utils.isEmpty(res.link_uri)) {\n                //如果没找到\n                return Result.failure(\"提示：请联系管理员开通权限！\");\n            } else {\n                //如果找到，让前端到跳到目标地址\n                String resUrl = GritUtil.buildDockUri(res);\n                return Result.succeed(resUrl);\n            }\n        }\n    }\n}\n\n//4，权限控制示例\n@Controller\npublic class DemoController{\n    //注解模式\n    @AuthPermissions(\"demo:admin\")\n    public void demo_ajax_del(String key){\n        //删除操作，有 demo:admin 权限的人才能操作\n    }\n\n    //代码模式\n    public void demo_ajax_del2(String key){\n        //删除操作，有 demo:admin 权限的人才能操作\n        if(GritClient.global().auth().hasPermission(subject_id, \"demo:admin\")){\n            return;\n        }\n    } \n}\n\n//5，构建动态菜单的示例\n@Component(\"view:header\")\npublic class HeaderTag implements TemplateDirectiveModel{\n    public void execute(){\n        //获取用户有权限的可见uri分组\n        List\u003cResourceGroup\u003e groupList = GritClient.global().auth().getUriGroupList(subjectId);\n\n        //获取分组的uri资源列表（内部是虚拟树）\n        List\u003cResourceEntity\u003e list = GritClient.global().auth().getUriListByGroup(subjectId, group.resource_id);\n        \n        //获取分组的第一个uri资源\n        ResourceEntity frist = GritClient.global().auth().getUriFristByGroup(subjectId, group.resource_id);\n    }\n}\n\n```\n\n实战参考：[https://gitee.com/noear/water/tree/master/wateradmin](https://gitee.com/noear/water/tree/master/wateradmin)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolonlab%2Fgrit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolonlab%2Fgrit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolonlab%2Fgrit/lists"}