123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package auth
- import (
- idtv1 "go-common/app/service/main/identify/api/grpc"
- "go-common/library/ecode"
- bm "go-common/library/net/http/blademaster"
- "go-common/library/net/metadata"
- "go-common/library/net/rpc/warden"
- "github.com/pkg/errors"
- )
- // Config is the identify config model.
- type Config struct {
- Identify *warden.ClientConfig
- // csrf switch.
- DisableCSRF bool
- }
- // Auth is the authorization middleware
- type Auth struct {
- idtv1.IdentifyClient
- conf *Config
- }
- // authFunc will return mid and error by given context
- type authFunc func(*bm.Context) (int64, error)
- var _defaultConf = &Config{
- Identify: nil,
- DisableCSRF: false,
- }
- // New is used to create an authorization middleware
- func New(conf *Config) *Auth {
- if conf == nil {
- conf = _defaultConf
- }
- identify, err := idtv1.NewClient(conf.Identify)
- if err != nil {
- panic(errors.WithMessage(err, "Failed to dial identify service"))
- }
- auth := &Auth{
- IdentifyClient: identify,
- conf: conf,
- }
- return auth
- }
- // User is used to mark path as access required.
- // If `access_key` is exist in request form, it will using mobile access policy.
- // Otherwise to web access policy.
- func (a *Auth) User(ctx *bm.Context) {
- req := ctx.Request
- if req.Form.Get("access_key") == "" {
- a.UserWeb(ctx)
- return
- }
- a.UserMobile(ctx)
- }
- // UserWeb is used to mark path as web access required.
- func (a *Auth) UserWeb(ctx *bm.Context) {
- a.midAuth(ctx, a.AuthCookie)
- }
- // UserMobile is used to mark path as mobile access required.
- func (a *Auth) UserMobile(ctx *bm.Context) {
- a.midAuth(ctx, a.AuthToken)
- }
- // Guest is used to mark path as guest policy.
- // If `access_key` is exist in request form, it will using mobile access policy.
- // Otherwise to web access policy.
- func (a *Auth) Guest(ctx *bm.Context) {
- req := ctx.Request
- if req.Form.Get("access_key") == "" {
- a.GuestWeb(ctx)
- return
- }
- a.GuestMobile(ctx)
- }
- // GuestWeb is used to mark path as web guest policy.
- func (a *Auth) GuestWeb(ctx *bm.Context) {
- a.guestAuth(ctx, a.AuthCookie)
- }
- // GuestMobile is used to mark path as mobile guest policy.
- func (a *Auth) GuestMobile(ctx *bm.Context) {
- a.guestAuth(ctx, a.AuthToken)
- }
- // AuthToken is used to authorize request by token
- func (a *Auth) AuthToken(ctx *bm.Context) (int64, error) {
- req := ctx.Request
- key := req.Form.Get("access_key")
- if key == "" {
- return 0, ecode.NoLogin
- }
- buvid := req.Header.Get("buvid")
- reply, err := a.GetTokenInfo(ctx, &idtv1.GetTokenInfoReq{Token: key, Buvid: buvid})
- if err != nil {
- return 0, err
- }
- if !reply.IsLogin {
- return 0, ecode.NoLogin
- }
- return reply.Mid, nil
- }
- // AuthCookie is used to authorize request by cookie
- func (a *Auth) AuthCookie(ctx *bm.Context) (int64, error) {
- req := ctx.Request
- ssDaCk, _ := req.Cookie("SESSDATA")
- if ssDaCk == nil {
- return 0, ecode.NoLogin
- }
- cookie := req.Header.Get("Cookie")
- reply, err := a.GetCookieInfo(ctx, &idtv1.GetCookieInfoReq{Cookie: cookie})
- if err != nil {
- return 0, err
- }
- if !reply.IsLogin {
- return 0, ecode.NoLogin
- }
- // check csrf
- clientCsrf := req.FormValue("csrf")
- if a.conf != nil && !a.conf.DisableCSRF && req.Method == "POST" {
- if clientCsrf != reply.Csrf {
- return 0, ecode.CsrfNotMatchErr
- }
- }
- return reply.Mid, nil
- }
- func (a *Auth) midAuth(ctx *bm.Context, auth authFunc) {
- mid, err := auth(ctx)
- if err != nil {
- ctx.JSON(nil, err)
- ctx.Abort()
- return
- }
- setMid(ctx, mid)
- }
- func (a *Auth) guestAuth(ctx *bm.Context, auth authFunc) {
- mid, err := auth(ctx)
- // no error happened and mid is valid
- if err == nil && mid > 0 {
- setMid(ctx, mid)
- return
- }
- ec := ecode.Cause(err)
- if ec.Equal(ecode.CsrfNotMatchErr) {
- ctx.JSON(nil, ec)
- ctx.Abort()
- return
- }
- }
- // set mid into context
- // NOTE: This method is not thread safe.
- func setMid(ctx *bm.Context, mid int64) {
- ctx.Set("mid", mid)
- if md, ok := metadata.FromContext(ctx); ok {
- md[metadata.Mid] = mid
- return
- }
- }
|