auth.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package auth
  2. import (
  3. idtv1 "go-common/app/service/main/identify/api/grpc"
  4. "go-common/library/ecode"
  5. bm "go-common/library/net/http/blademaster"
  6. "go-common/library/net/metadata"
  7. "go-common/library/net/rpc/warden"
  8. "github.com/pkg/errors"
  9. )
  10. // Config is the identify config model.
  11. type Config struct {
  12. Identify *warden.ClientConfig
  13. // csrf switch.
  14. DisableCSRF bool
  15. }
  16. // Auth is the authorization middleware
  17. type Auth struct {
  18. idtv1.IdentifyClient
  19. conf *Config
  20. }
  21. // authFunc will return mid and error by given context
  22. type authFunc func(*bm.Context) (int64, error)
  23. var _defaultConf = &Config{
  24. Identify: nil,
  25. DisableCSRF: false,
  26. }
  27. // New is used to create an authorization middleware
  28. func New(conf *Config) *Auth {
  29. if conf == nil {
  30. conf = _defaultConf
  31. }
  32. identify, err := idtv1.NewClient(conf.Identify)
  33. if err != nil {
  34. panic(errors.WithMessage(err, "Failed to dial identify service"))
  35. }
  36. auth := &Auth{
  37. IdentifyClient: identify,
  38. conf: conf,
  39. }
  40. return auth
  41. }
  42. // User is used to mark path as access required.
  43. // If `access_key` is exist in request form, it will using mobile access policy.
  44. // Otherwise to web access policy.
  45. func (a *Auth) User(ctx *bm.Context) {
  46. req := ctx.Request
  47. if req.Form.Get("access_key") == "" {
  48. a.UserWeb(ctx)
  49. return
  50. }
  51. a.UserMobile(ctx)
  52. }
  53. // UserWeb is used to mark path as web access required.
  54. func (a *Auth) UserWeb(ctx *bm.Context) {
  55. a.midAuth(ctx, a.AuthCookie)
  56. }
  57. // UserMobile is used to mark path as mobile access required.
  58. func (a *Auth) UserMobile(ctx *bm.Context) {
  59. a.midAuth(ctx, a.AuthToken)
  60. }
  61. // Guest is used to mark path as guest policy.
  62. // If `access_key` is exist in request form, it will using mobile access policy.
  63. // Otherwise to web access policy.
  64. func (a *Auth) Guest(ctx *bm.Context) {
  65. req := ctx.Request
  66. if req.Form.Get("access_key") == "" {
  67. a.GuestWeb(ctx)
  68. return
  69. }
  70. a.GuestMobile(ctx)
  71. }
  72. // GuestWeb is used to mark path as web guest policy.
  73. func (a *Auth) GuestWeb(ctx *bm.Context) {
  74. a.guestAuth(ctx, a.AuthCookie)
  75. }
  76. // GuestMobile is used to mark path as mobile guest policy.
  77. func (a *Auth) GuestMobile(ctx *bm.Context) {
  78. a.guestAuth(ctx, a.AuthToken)
  79. }
  80. // AuthToken is used to authorize request by token
  81. func (a *Auth) AuthToken(ctx *bm.Context) (int64, error) {
  82. req := ctx.Request
  83. key := req.Form.Get("access_key")
  84. if key == "" {
  85. return 0, ecode.NoLogin
  86. }
  87. buvid := req.Header.Get("buvid")
  88. reply, err := a.GetTokenInfo(ctx, &idtv1.GetTokenInfoReq{Token: key, Buvid: buvid})
  89. if err != nil {
  90. return 0, err
  91. }
  92. if !reply.IsLogin {
  93. return 0, ecode.NoLogin
  94. }
  95. return reply.Mid, nil
  96. }
  97. // AuthCookie is used to authorize request by cookie
  98. func (a *Auth) AuthCookie(ctx *bm.Context) (int64, error) {
  99. req := ctx.Request
  100. ssDaCk, _ := req.Cookie("SESSDATA")
  101. if ssDaCk == nil {
  102. return 0, ecode.NoLogin
  103. }
  104. cookie := req.Header.Get("Cookie")
  105. reply, err := a.GetCookieInfo(ctx, &idtv1.GetCookieInfoReq{Cookie: cookie})
  106. if err != nil {
  107. return 0, err
  108. }
  109. if !reply.IsLogin {
  110. return 0, ecode.NoLogin
  111. }
  112. // check csrf
  113. clientCsrf := req.FormValue("csrf")
  114. if a.conf != nil && !a.conf.DisableCSRF && req.Method == "POST" {
  115. if clientCsrf != reply.Csrf {
  116. return 0, ecode.CsrfNotMatchErr
  117. }
  118. }
  119. return reply.Mid, nil
  120. }
  121. func (a *Auth) midAuth(ctx *bm.Context, auth authFunc) {
  122. mid, err := auth(ctx)
  123. if err != nil {
  124. ctx.JSON(nil, err)
  125. ctx.Abort()
  126. return
  127. }
  128. setMid(ctx, mid)
  129. }
  130. func (a *Auth) guestAuth(ctx *bm.Context, auth authFunc) {
  131. mid, err := auth(ctx)
  132. // no error happened and mid is valid
  133. if err == nil && mid > 0 {
  134. setMid(ctx, mid)
  135. return
  136. }
  137. ec := ecode.Cause(err)
  138. if ec.Equal(ecode.CsrfNotMatchErr) {
  139. ctx.JSON(nil, ec)
  140. ctx.Abort()
  141. return
  142. }
  143. }
  144. // set mid into context
  145. // NOTE: This method is not thread safe.
  146. func setMid(ctx *bm.Context, mid int64) {
  147. ctx.Set("mid", mid)
  148. if md, ok := metadata.FromContext(ctx); ok {
  149. md[metadata.Mid] = mid
  150. return
  151. }
  152. }