permlib.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package permlib
  2. import (
  3. "context"
  4. "net/http"
  5. )
  6. // PermDecl 权限声明,用于静态注册(permgen 插件生成)
  7. type PermDecl struct {
  8. Code string
  9. Name string
  10. }
  11. // RoutePermDecl 路由-权限映射,用于静态注册
  12. type RoutePermDecl struct {
  13. Method string
  14. Path string
  15. PermCode string
  16. DataCode string // 配对的 data 权限 code
  17. }
  18. // FieldNode 树形字段权限节点,支持任意深度嵌套
  19. type FieldNode struct {
  20. Fields map[string]string // jsonName → permCode(当前层需过滤的字段)
  21. Nested map[string]*FieldNode // jsonName → 子节点(有嵌套结构的字段)
  22. }
  23. // FieldPermMap 字段权限映射,用于静态注册(替代反射)
  24. type FieldPermMap struct {
  25. Request *FieldNode
  26. Response *FieldNode
  27. }
  28. type Engine struct {
  29. cfg Config
  30. client *grpcClient
  31. cache *permCache
  32. staticPerms []PermDecl
  33. routePerms map[string]RoutePermDecl // "METHOD /path" → RoutePermDecl
  34. fieldPerms map[string]FieldPermMap // "METHOD /path" → FieldPermMap
  35. }
  36. type LoginResult struct {
  37. AccessToken string
  38. RefreshToken string
  39. Expires int64
  40. UserId int64
  41. Username string
  42. Nickname string
  43. MemberType string
  44. Perms []string
  45. }
  46. type RefreshTokenResult struct {
  47. AccessToken string
  48. RefreshToken string
  49. Expires int64
  50. Perms []string
  51. }
  52. type UserPermsResult struct {
  53. Perms []string
  54. MemberType string
  55. }
  56. func New(cfg Config) (*Engine, error) {
  57. cfg.defaults()
  58. if err := cfg.validate(); err != nil {
  59. return nil, err
  60. }
  61. client, err := newGRPCClient(cfg.PermServerAddr)
  62. if err != nil {
  63. return nil, err
  64. }
  65. return &Engine{
  66. cfg: cfg,
  67. client: client,
  68. cache: newPermCache(cfg.CacheTTL),
  69. routePerms: make(map[string]RoutePermDecl),
  70. fieldPerms: make(map[string]FieldPermMap),
  71. }, nil
  72. }
  73. // RegisterPerms 静态注册权限声明(由 permgen 插件生成的代码调用)
  74. func (e *Engine) RegisterPerms(perms []PermDecl) {
  75. e.staticPerms = append(e.staticPerms, perms...)
  76. }
  77. // RegisterRoutePerms 静态注册路由-权限映射(由 permgen 插件生成的代码调用)
  78. func (e *Engine) RegisterRoutePerms(decls []RoutePermDecl) {
  79. for _, d := range decls {
  80. key := d.Method + " " + d.Path
  81. e.routePerms[key] = d
  82. }
  83. }
  84. // RegisterFieldPerms 静态注册字段权限映射(由 permgen 插件生成的代码调用,替代反射)
  85. func (e *Engine) RegisterFieldPerms(m map[string]FieldPermMap) {
  86. for k, v := range m {
  87. e.fieldPerms[k] = v
  88. }
  89. }
  90. func (e *Engine) Start(ctx context.Context) error {
  91. perms := e.collectPerms()
  92. if len(perms) > 0 {
  93. if err := e.syncPerms(ctx, perms); err != nil {
  94. return err
  95. }
  96. }
  97. return nil
  98. }
  99. // Login 调用权限系统 gRPC Login 接口
  100. func (e *Engine) Login(ctx context.Context, username, password string) (*LoginResult, error) {
  101. resp, err := e.client.login(ctx, e.cfg.ProductCode, username, password)
  102. if err != nil {
  103. return nil, err
  104. }
  105. return &LoginResult{
  106. AccessToken: resp.AccessToken,
  107. RefreshToken: resp.RefreshToken,
  108. Expires: resp.Expires,
  109. UserId: resp.UserId,
  110. Username: resp.Username,
  111. Nickname: resp.Nickname,
  112. MemberType: resp.MemberType,
  113. Perms: resp.Perms,
  114. }, nil
  115. }
  116. // RefreshToken 调用权限系统 gRPC RefreshToken 接口
  117. func (e *Engine) RefreshToken(ctx context.Context, refreshToken string) (*RefreshTokenResult, error) {
  118. resp, err := e.client.refreshToken(ctx, refreshToken, e.cfg.ProductCode)
  119. if err != nil {
  120. return nil, err
  121. }
  122. return &RefreshTokenResult{
  123. AccessToken: resp.AccessToken,
  124. RefreshToken: resp.RefreshToken,
  125. Expires: resp.Expires,
  126. Perms: resp.Perms,
  127. }, nil
  128. }
  129. // GetUserPerms 查询指定用户在当前产品下的权限列表,使用 appKey/appSecret 做服务间认证
  130. // 适用于定时任务、服务间调用等不走 token 验证的场景
  131. func (e *Engine) GetUserPerms(ctx context.Context, userId int64) (*UserPermsResult, error) {
  132. resp, err := e.client.getUserPerms(ctx, e.cfg.AppKey, e.cfg.AppSecret, userId, e.cfg.ProductCode)
  133. if err != nil {
  134. return nil, err
  135. }
  136. return &UserPermsResult{
  137. Perms: resp.Perms,
  138. MemberType: resp.MemberType,
  139. }, nil
  140. }
  141. // Logout 调用权限系统 gRPC Logout 接口,使 accessToken 对应用户的所有令牌立即失效
  142. func (e *Engine) Logout(ctx context.Context, accessToken string) error {
  143. return e.client.logout(ctx, accessToken)
  144. }
  145. // AuthMiddleware 返回鉴权 handler,供产品端中间件直接调用
  146. func (e *Engine) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
  147. return e.authMiddleware(next)
  148. }