你的单体服务架构是否遇到一些问题, 不能满足业务需求? 那么微服务会是好的解决方案.
Cinch是一套轻量级微服务脚手架, 基于Kratos, 节省基础服务搭建时间, 快速投入业务开发.
我们参考了Go的许多微服务架构, 结合实际需求, 最终选择简洁的Kratos作为基石(B站架构), 从架构的设计思路以及代码的书写格式和我们非常匹配.
cinch意为简单的事, 小菜. 希望把复杂的事变得简单, 提升开发效率.
若你想深入学习微服务每个组件, 建议直接看Kratos官方文档. 本项目整合一些业务常用组件, 开箱即用, 并不会把每个组件都介绍那么详细.
Go
- 当前Go版本直接上v1.20
Proto
- proto协议同时开启gRPC & HTTP支持, 只需开发一次接口, 不用写两套Jwt
- 认证, 用户登入登出一键搞定Action
- 权限, 基于行为的权限校验Redis
- 缓存, 内置防缓存穿透/缓存击穿/缓存雪崩示例Gorm
- 数据库ORM管理框架, 可自行扩展多种数据库类型, 目前使用MySQL, 其他自行扩展Gorm Gen
- Gorm实体自动生成, 无需再写数据库实体映射Tenant
- 基于Gorm的schema层面的多租户(一个租户一个数据库schema)SqlMigrate
- 数据库迁移工具, 每次更新平滑迁移Asynq
- 分布式定时任务(异步任务)Log
- 日志, 在Kratos基础上增加一层包装, 无需每个方法传入Embed
- go 1.16文件嵌入属性, 轻松将静态文件打包到编译后的二进制应用中Opentelemetry
- 链路追踪, 跨服务调用可快速追踪完整链路Idempotent
- 接口幂等性(解决重复点击或提交)Pprof
- 内置性能分析开关, 对并发/性能测试友好Wire
- 依赖注入, 编译时完成依赖注入Swagger
- Api文档一键生成, 无需在代码里写注解I18n
- 国际化支持, 简单切换多语言
建议直接使用最后一个版本
git clone -b v1.0.3 https://github.com/go-cinch/auth
Auth是基于layout生成的一个通用权限验证微服务, 节省鉴权服务搭建时间, 快速投入业务开发.
Golang主流的权限管理基本上用的是Casbin, 曾经的项目中也用到过, 如gin-web, 设计模式很好, 但实际使用过程中遇到一些问题
以RBAC为例以及结合常见的web管理系统, 你大概需要这么设计
- api表 - 接口表, 存储所有的api, 如
GET /user
,POST /login
(method+path) - casbin表 - casbin关系表, 存储对象和api之间的关系, 如用户admin有
GET /user
的访问权限, 数据记录可能是v0=admin, v1=GET, v2=/user
- menu表 - 菜单表(可能包含关联表, 这里不细说), 存储所有的菜单
- 和api关联, 如
用户管理
菜单下有GET /user
,POST /user
,PATCH /user
,DELETE /user
- 和role关联, 如角色是超级管理员可以展示所有页面, 访客只能查看首页
- 和api关联, 如
- 若还需要增加单个按钮, 那需要btn表, 和menu类似
- 若还需要单个用户权限不一样, 那user表与menu/btn要建立关联
- 若还需要用户组权限, 那用户组与上面的表要建立关联
那么问题来了
- 新增或删除接口, 你怎么维护上述各个表之间的关联关系?
- app没有菜单, 怎么来设计
或许这并不是casbin的问题, 这是业务层的问题. 你有更好的方案欢迎讨论
name
- 名称, 可以重复, 定义行为名, 描述当前action用途code
- 唯一标识, 主要用于其他表关联word
- 英文关键字, 唯一, 方便前端展示resource
- 资源列表(\n隔开), 可以是http接口地址, 也可以是grpc接口地址menu
- 菜单列表(\n隔开), 和前端路由有关btn
- 按钮列表(\n隔开), 和前端有关
Tip: menu/btn是给前端看的, 前端来决定是否需要显示, 后端不单独存储menu表/btn表
action
- 行为code列表(逗号隔开), 包含用户/角色/用户组具有的所有行为
优点
- 权限变更高效
- 程序员只需关心action表, 修改action表对应内容即可
- 使用者勾选或添加action, action通过name显示, 简单易懂
- action不区分pc/app
- 减少关联表
缺点
- 增加冗余性(这个和减少关联表是相悖的)
- 菜单等更新由前端管理, 若需更新, 必须重新发布前端代码
http接口推荐配合nginx auth_request使用
- 所有请求全部通过auth_request转发至
/permission
- 校验当前用户是否有resource的权限, 有直接返回(resource=
method
+path
) - 校验当前用户所在角色是否有参数resource的权限, 有直接返回
- 校验当前用户所在用户组是否有参数resource的权限
grpc无法使用nginx auth_request
- 所有请求直接到各自微服务
- 通过权限中间件转发到
/auth.v1.Auth/Permission
, auth服务执行后续逻辑 - 校验当前用户是否有resource的权限, 有直接返回(resource=
/game.v1.Game/FindGame
) - 校验当前用户所在角色是否有参数resource的权限, 有直接返回
- 校验当前用户所在用户组是否有参数resource的权限
权限源码参见auth.Permission
中间件参加layout.Permission
/auth.v1.Auth/Register
- 用户注册/auth.v1.Auth/Pwd
- 修改密码/auth.v1.Auth/Status
- 获取用户状态, 是否锁定/需要输入验证码等/auth.v1.Auth/Captcha
- 获取验证码base64图片, 默认4位数字/auth.v1.Auth/Login
- 登入, 获取jwt token/auth.v1.Auth/Logout
- 登出/auth.v1.Auth/Refresh
- 刷新jwt token/auth.v1.Auth/Idempotent
- 获取幂等性token(登陆后)/auth.v1.Auth/Info
- 获取用户信息(登陆后)
其他接口是Action/User/Role/UserGroup的CRUD, 完整接口参见auth.proto
微服务设计**可参考Kratos