middleware.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. package middleware
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/google/uuid"
  6. "github.com/pkg/errors"
  7. "github.com/sirupsen/logrus"
  8. "go-micro.dev/v4"
  9. "go-micro.dev/v4/auth"
  10. "go-micro.dev/v4/metadata"
  11. "go-micro.dev/v4/server"
  12. "sghgogs.com/sghblog/authorization-service/utils/authutil"
  13. "sghgogs.com/sghblog/common"
  14. "sghgogs.com/sghblog/common/errorcode"
  15. "sort"
  16. "strings"
  17. )
  18. const (
  19. // BearerScheme used for Authorization header.
  20. BearerScheme = "Bearer "
  21. // ScopePublic is the scope applied to a rule to allow access to the public.
  22. ScopePublic = ""
  23. // ScopeAccount is the scope applied to a rule to limit to users with any valid account.
  24. ScopeAccount = "*"
  25. name = "authorizationservice"
  26. )
  27. var (
  28. // ErrInvalidToken is when the token provided is not valid.
  29. ErrInvalidToken = errors.New("invalid token provided")
  30. // ErrForbidden is when a user does not have the necessary scope to access a resource.
  31. ErrForbidden = errors.New("resource forbidden")
  32. )
  33. // type Access int
  34. const (
  35. // AccessGranted to a resource.
  36. AccessGranted auth.Access = iota
  37. // AccessDenied to a resource.
  38. AccessDenied
  39. )
  40. func Verify(rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error {
  41. // the rule is only to be applied if the type matches the resource or is catch-all (*)
  42. validTypes := []string{"*", res.Type}
  43. // the rule is only to be applied if the name matches the resource or is catch-all (*)
  44. validNames := []string{"*", res.Name}
  45. // rules can have wildcard excludes on endpoints since this can also be a path for web services,
  46. // e.g. /foo/* would include /foo/bar. We also want to check for wildcards and the exact endpoint
  47. validEndpoints := []string{"*", res.Endpoint}
  48. if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
  49. for i := 1; i < len(comps)+1; i++ {
  50. wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
  51. validEndpoints = append(validEndpoints, wildcard)
  52. }
  53. }
  54. // filter the rules to the ones which match the criteria above
  55. filteredRules := make([]*auth.Rule, 0)
  56. for _, rule := range rules {
  57. if !include(validTypes, rule.Resource.Type) {
  58. continue
  59. }
  60. if !include(validNames, rule.Resource.Name) {
  61. continue
  62. }
  63. if !include(validEndpoints, rule.Resource.Endpoint) {
  64. continue
  65. }
  66. filteredRules = append(filteredRules, rule)
  67. }
  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. // loop through the rules and check for a rule which applies to this account
  73. for _, rule := range filteredRules {
  74. // a blank scope indicates the rule applies to everyone, even nil accounts
  75. if rule.Scope == ScopePublic && rule.Access == AccessDenied {
  76. return ErrForbidden
  77. } else if rule.Scope == ScopePublic && rule.Access == AccessGranted {
  78. return nil
  79. }
  80. // all further checks require an account
  81. if acc == nil {
  82. continue
  83. }
  84. // this rule applies to any account
  85. if rule.Scope == ScopeAccount && rule.Access == AccessDenied {
  86. return ErrForbidden
  87. } else if rule.Scope == ScopeAccount && rule.Access == AccessGranted {
  88. return nil
  89. }
  90. // 去掉首尾的方括号
  91. // if the account has the necessary scope
  92. fmt.Println(acc.Scopes, rule.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. adminLogout = &auth.Resource{
  141. Type: "user",
  142. Name: name,
  143. Endpoint: "CommonService.AdminLogout",
  144. }
  145. adminProfile = &auth.Resource{
  146. Type: "user",
  147. Name: name,
  148. Endpoint: "CommonService.AdminProfile",
  149. }
  150. listAdminRoles = &auth.Resource{
  151. Type: "user",
  152. Name: name,
  153. Endpoint: "AdminRoleService.ListAdminRoles",
  154. }
  155. updateAdminRole = &auth.Resource{
  156. Type: "user",
  157. Name: name,
  158. Endpoint: "AdminRoleService.UpdateAdminRole",
  159. }
  160. createAdminRole = &auth.Resource{
  161. Type: "user",
  162. Name: name,
  163. Endpoint: "AdminRoleService.CreateAdminRole",
  164. }
  165. deleteAdminRole = &auth.Resource{
  166. Type: "user",
  167. Name: name,
  168. Endpoint: "AdminRoleService.DeleteAdminRole",
  169. }
  170. getAdminRole = &auth.Resource{
  171. Type: "user",
  172. Name: name,
  173. Endpoint: "AdminRoleService.GetAdminRole",
  174. }
  175. toggleAdminRole = &auth.Resource{
  176. Type: "user",
  177. Name: name,
  178. Endpoint: "AdminRoleService.ToggleAdminRole",
  179. }
  180. retrieveEnabledRoles = &auth.Resource{
  181. Type: "user",
  182. Name: name,
  183. Endpoint: "AdminRoleService.RetrieveEnabledRoles",
  184. }
  185. getUnassignedAdminRoles = &auth.Resource{
  186. Type: "user",
  187. Name: name,
  188. Endpoint: "AdminUserService.GetUnassignedAdminRoles",
  189. }
  190. getAdminUser = &auth.Resource{
  191. Type: "user",
  192. Name: name,
  193. Endpoint: "AdminUserService.GetAdminUser",
  194. }
  195. createAdminUser = &auth.Resource{
  196. Type: "user",
  197. Name: name,
  198. Endpoint: "AdminUserService.CreateAdminUser",
  199. }
  200. associateAdminUserWithRole = &auth.Resource{
  201. Type: "user",
  202. Name: name,
  203. Endpoint: "AdminUserService.AssociateAdminUserWithRole",
  204. }
  205. updateAdminUser = &auth.Resource{
  206. Type: "user",
  207. Name: name,
  208. Endpoint: "AdminUserService.UpdateAdminUser",
  209. }
  210. revokeAdminUserWithRole = &auth.Resource{
  211. Type: "user",
  212. Name: name,
  213. Endpoint: "AdminUserService.RevokeAdminUserWithRole",
  214. }
  215. listAdminUsers = &auth.Resource{
  216. Type: "user",
  217. Name: name,
  218. Endpoint: "AdminUserService.ListAdminUsers",
  219. }
  220. retrieveEnabledUsers = &auth.Resource{
  221. Type: "user",
  222. Name: name,
  223. Endpoint: "AdminUserService.RetrieveEnabledUsers",
  224. }
  225. deleteAdminUser = &auth.Resource{
  226. Type: "user",
  227. Name: name,
  228. Endpoint: "AdminUserService.DeleteAdminUser",
  229. }
  230. toggleAdminUser = &auth.Resource{
  231. Type: "user",
  232. Name: name,
  233. Endpoint: "AdminUserService.ToggleAdminUser",
  234. }
  235. getAuthentication = &auth.Resource{
  236. Type: "user",
  237. Name: name,
  238. Endpoint: "AuthenticationService.GetAuthentication",
  239. }
  240. // catchallResource
  241. rulesItems = []*auth.Rule{
  242. // {Scope: "*", Resource: catchallResource}, toggleAdminRole
  243. {Scope: "admin", Resource: adminLogout, ID: uuid.New().String(), Priority: 1},
  244. {Scope: "admin", Resource: adminProfile, ID: uuid.New().String(), Priority: 1},
  245. {Scope: "admin", Resource: listAdminRoles, ID: uuid.New().String(), Priority: 1},
  246. {Scope: "admin", Resource: updateAdminRole, ID: uuid.New().String(), Priority: 1},
  247. {Scope: "admin", Resource: createAdminRole, ID: uuid.New().String(), Priority: 1},
  248. {Scope: "admin", Resource: toggleAdminRole, ID: uuid.New().String(), Priority: 1},
  249. {Scope: "admin", Resource: getUnassignedAdminRoles, ID: uuid.New().String(), Priority: 1},
  250. {Scope: "admin", Resource: deleteAdminRole, ID: uuid.New().String(), Priority: 1},
  251. {Scope: "admin", Resource: getAdminRole, ID: uuid.New().String(), Priority: 1},
  252. {Scope: "admin", Resource: retrieveEnabledRoles, ID: uuid.New().String(), Priority: 1},
  253. {Scope: "admin", Resource: getAdminUser, ID: uuid.New().String(), Priority: 1},
  254. {Scope: "admin", Resource: createAdminUser, ID: uuid.New().String(), Priority: 1},
  255. {Scope: "admin", Resource: associateAdminUserWithRole, ID: uuid.New().String(), Priority: 1},
  256. {Scope: "admin", Resource: updateAdminUser, ID: uuid.New().String(), Priority: 1},
  257. {Scope: "admin", Resource: revokeAdminUserWithRole, ID: uuid.New().String(), Priority: 1},
  258. {Scope: "admin", Resource: listAdminUsers, ID: uuid.New().String(), Priority: 1},
  259. {Scope: "admin", Resource: retrieveEnabledUsers, ID: uuid.New().String(), Priority: 1},
  260. {Scope: "admin", Resource: deleteAdminUser, ID: uuid.New().String(), Priority: 1},
  261. {Scope: "admin", Resource: toggleAdminUser, ID: uuid.New().String(), Priority: 1},
  262. {Scope: "kube_admin", Resource: getAuthentication, ID: uuid.New().String(), Priority: 1},
  263. }
  264. )
  265. func NewAuthWrapper(service micro.Service) server.HandlerWrapper {
  266. return func(h server.HandlerFunc) server.HandlerFunc {
  267. return func(ctx context.Context, req server.Request, rsp interface{}) error {
  268. logrus.Infof("[wrapper] server request: %v", req.Endpoint())
  269. if req.Endpoint() == "CommonService.AdminLogin" {
  270. return h(ctx, req, rsp)
  271. }
  272. if req.Endpoint() == "AdminUserService.GetAdminUserAssociatedRoles" {
  273. return h(ctx, req, rsp)
  274. }
  275. // Fetch metadata from context (request headers).
  276. md, b := metadata.FromContext(ctx)
  277. if !b {
  278. return errorcode.Unauthorized("authorization service", common.ErrorMessage[common.UnauthorizedErrorCode])
  279. // errors.New("no metadata found")
  280. }
  281. // local ip of service
  282. fmt.Println("local ip is", md["Local"])
  283. // remote ip of caller
  284. fmt.Println("remote ip is", md["Remote"])
  285. // Get auth header.
  286. authHeader, ok := md["Authorization"]
  287. if !ok || !strings.HasPrefix(authHeader, auth.BearerScheme) {
  288. logrus.Error("no auth token provided")
  289. return errorcode.Unauthorized("authorization service", common.ErrorMessage[common.UnauthorizedErrorCode])
  290. }
  291. // Extract auth token.
  292. token := strings.TrimPrefix(authHeader, auth.BearerScheme)
  293. // Extract account from token.
  294. token = strings.TrimSpace(token)
  295. a := service.Options().Auth
  296. acc, err := a.Inspect(token)
  297. fmt.Println("acc", acc)
  298. if err != nil {
  299. return errorcode.Unauthorized("authorization service", common.ErrorMessage[common.TokenInvalidErrorCode])
  300. }
  301. // 校验redis 存储数据
  302. blacklisted, err := authutil.JWTAuthService.IsBlacklisted(token)
  303. fmt.Println("blacklisted", blacklisted)
  304. if err == nil && blacklisted {
  305. return errorcode.Unauthorized("authorization service", common.ErrorMessage[common.ExpiredLonInAgainErrorCode])
  306. }
  307. // Create resource for current endpoint from request headers.
  308. currentResource := auth.Resource{
  309. Type: "user",
  310. Name: md["Micro-Service"],
  311. Endpoint: md["Micro-Endpoint"],
  312. }
  313. // Verify if account has access. 验证帐户是否具有访问权限。
  314. if err = Verify(rulesItems, acc, &currentResource); err != nil {
  315. return errorcode.Unauthorized("authorization service", common.ErrorMessage[common.NoAccessErrorCode])
  316. }
  317. // 验证通过后记录操作日志
  318. logrus.Infof("User %s is performing operation %s body %v", acc.ID, req.Endpoint(), req.Body())
  319. return h(ctx, req, rsp)
  320. }
  321. }
  322. }