middleware.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. package middleware
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/pkg/errors"
  6. "github.com/sirupsen/logrus"
  7. "go-micro.dev/v4"
  8. "go-micro.dev/v4/auth"
  9. "go-micro.dev/v4/metadata"
  10. "go-micro.dev/v4/server"
  11. "sghgogs.com/micro/common"
  12. "sghgogs.com/micro/common/errorcode"
  13. "sghgogs.com/micro/k8s-service/utils/authutil"
  14. "sort"
  15. "strings"
  16. )
  17. const (
  18. // BearerScheme used for Authorization header.
  19. BearerScheme = "Bearer "
  20. // ScopePublic is the scope applied to a rule to allow access to the public.
  21. ScopePublic = ""
  22. // ScopeAccount is the scope applied to a rule to limit to users with any valid account.
  23. ScopeAccount = "*"
  24. name = "kubernetesservice"
  25. )
  26. var (
  27. // ErrInvalidToken is when the token provided is not valid.
  28. ErrInvalidToken = errors.New("invalid token provided")
  29. // ErrForbidden is when a user does not have the necessary scope to access a resource.
  30. ErrForbidden = errors.New("resource forbidden")
  31. )
  32. // type Access int
  33. const (
  34. // AccessGranted to a resource.
  35. AccessGranted auth.Access = iota
  36. // AccessDenied to a resource.
  37. AccessDenied
  38. )
  39. func Verify(rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error {
  40. // the rule is only to be applied if the type matches the resource or is catch-all (*)
  41. validTypes := []string{"*", res.Type}
  42. // the rule is only to be applied if the name matches the resource or is catch-all (*)
  43. validNames := []string{"*", res.Name}
  44. // rules can have wildcard excludes on endpoints since this can also be a path for web services,
  45. // e.g. /foo/* would include /foo/bar. We also want to check for wildcards and the exact endpoint
  46. validEndpoints := []string{"*", res.Endpoint}
  47. if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
  48. for i := 1; i < len(comps)+1; i++ {
  49. wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
  50. validEndpoints = append(validEndpoints, wildcard)
  51. }
  52. }
  53. // filter the rules to the ones which match the criteria above
  54. filteredRules := make([]*auth.Rule, 0)
  55. for _, rule := range rules {
  56. if !include(validTypes, rule.Resource.Type) {
  57. continue
  58. }
  59. if !include(validNames, rule.Resource.Name) {
  60. continue
  61. }
  62. if !include(validEndpoints, rule.Resource.Endpoint) {
  63. continue
  64. }
  65. filteredRules = append(filteredRules, rule)
  66. }
  67. fmt.Println("2-")
  68. // sort the filtered rules by priority, highest to lowest
  69. sort.SliceStable(filteredRules, func(i, j int) bool {
  70. return filteredRules[i].Priority > filteredRules[j].Priority
  71. })
  72. fmt.Println("3-")
  73. // loop through the rules and check for a rule which applies to this account
  74. for _, rule := range filteredRules {
  75. // a blank scope indicates the rule applies to everyone, even nil accounts
  76. if rule.Scope == ScopePublic && rule.Access == AccessDenied {
  77. return ErrForbidden
  78. } else if rule.Scope == ScopePublic && rule.Access == AccessGranted {
  79. return nil
  80. }
  81. // all further checks require an account
  82. if acc == nil {
  83. continue
  84. }
  85. // this rule applies to any account
  86. if rule.Scope == ScopeAccount && rule.Access == AccessDenied {
  87. return ErrForbidden
  88. } else if rule.Scope == ScopeAccount && rule.Access == AccessGranted {
  89. return nil
  90. }
  91. // 去掉首尾的方括号
  92. // if the account has the necessary scope
  93. if include(acc.Scopes, rule.Scope) && rule.Access == AccessDenied {
  94. return ErrForbidden
  95. } else if include(acc.Scopes, rule.Scope) && rule.Access == AccessGranted {
  96. return nil
  97. }
  98. }
  99. // if no rules matched then return forbidden
  100. return ErrForbidden
  101. }
  102. // include is a helper function which checks to see if the slice contains the value. includes is
  103. // not case sensitive.
  104. func include(slice []string, val string) bool {
  105. // str := slice
  106. if len(slice) > 0 {
  107. if strings.Contains(slice[0], ",") {
  108. data := strings.Split(slice[0], ",")
  109. // 打印结果
  110. for _, s := range data {
  111. if s == "super_admin" {
  112. return true
  113. }
  114. if strings.EqualFold(s, val) {
  115. return true
  116. }
  117. }
  118. // 判断超级管理员
  119. } else {
  120. // 判断超级管理员
  121. for _, s := range slice {
  122. if s == "super_admin" {
  123. return true
  124. }
  125. if strings.EqualFold(s, val) {
  126. return true
  127. }
  128. }
  129. }
  130. return false
  131. }
  132. return false
  133. }
  134. // var (
  135. // // catchallResource = &auth.Resource{
  136. // // Type: "*",
  137. // // Name: "*",
  138. // // Endpoint: "*",
  139. // // }
  140. // //
  141. //
  142. // getAuthentication = &auth.Resource{
  143. // Type: "user",
  144. // Name: name,
  145. // Endpoint: "AuthenticationService.GetAuthentication",
  146. // }
  147. // // catchallResource
  148. // rulesItems = []*auth.Rule{
  149. // // {Scope: "*", Resource: catchallResource}, toggleAdminRole
  150. // {Scope: "kubernetes", Resource: getAuthentication, ID: uuid.New().String(), Priority: 1},
  151. // }
  152. // )
  153. func NewAuthWrapper(service micro.Service) server.HandlerWrapper {
  154. return func(h server.HandlerFunc) server.HandlerFunc {
  155. return func(ctx context.Context, req server.Request, rsp interface{}) error {
  156. logrus.Infof("[wrapper] server request: %v", req.Endpoint())
  157. if req.Endpoint() == "CommonService.AdminLogin" {
  158. return h(ctx, req, rsp)
  159. }
  160. if req.Endpoint() == "AdminUserService.GetAdminUserAssociatedRoles" {
  161. return h(ctx, req, rsp)
  162. }
  163. // Fetch metadata from context (request headers).
  164. md, b := metadata.FromContext(ctx)
  165. if !b {
  166. return errorcode.Unauthorized("kubernetes service", common.ErrorMessage[common.UnauthorizedErrorCode])
  167. // errors.New("no metadata found")
  168. }
  169. // local ip of service
  170. fmt.Println("local ip is", md["Local"])
  171. // remote ip of caller
  172. fmt.Println("remote ip is", md["Remote"])
  173. // Get auth header.
  174. authHeader, ok := md["Authorization"]
  175. if !ok || !strings.HasPrefix(authHeader, auth.BearerScheme) {
  176. logrus.Error("no auth token provided")
  177. return errorcode.Unauthorized("kubernetes service", common.ErrorMessage[common.UnauthorizedErrorCode])
  178. }
  179. // Extract auth token.
  180. token := strings.TrimPrefix(authHeader, auth.BearerScheme)
  181. // Extract account from token.
  182. token = strings.TrimSpace(token)
  183. a := service.Options().Auth
  184. acc, err := a.Inspect(token)
  185. fmt.Println("acc", acc)
  186. if err != nil {
  187. return errorcode.Unauthorized("kubernetes service", common.ErrorMessage[common.TokenInvalidErrorCode])
  188. }
  189. // 校验redis 存储数据
  190. blacklisted, err := authutil.JWTAuthService.IsBlacklisted(token)
  191. if err == nil && blacklisted {
  192. return errorcode.Unauthorized("kubernetes service", common.ErrorMessage[common.ExpiredLonInAgainErrorCode])
  193. }
  194. // Create resource for current endpoint from request headers.
  195. currentResource := auth.Resource{
  196. Type: "user",
  197. Name: md["Micro-Service"],
  198. Endpoint: md["Micro-Endpoint"],
  199. }
  200. fmt.Println("acc.Scopes", acc.Scopes)
  201. // Verify if account has access. 验证帐户是否具有访问权限。
  202. if err = Verify(authutil.JWTAuthService.GetRuleItems(), acc, &currentResource); err != nil {
  203. return errorcode.Unauthorized("kubernetes service", common.ErrorMessage[common.NoAccessErrorCode])
  204. }
  205. // 验证通过后记录操作日志x
  206. logrus.Infof("User %s is performing operation %s body %v", acc.ID, req.Endpoint(), req.Body())
  207. return h(ctx, req, rsp)
  208. }
  209. }
  210. }