package middlewares import ( "context" "backend/common/consts" "backend/modules/users" "backend/pkg/pg" "backend/providers/jwt" "backend/providers/wechat" "github.com/gofiber/fiber/v3" "github.com/jinzhu/copier" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) // @provider type Middlewares struct { client *wechat.Client userSvc *users.Service jwt *jwt.JWT log *log.Entry `inject:"false"` } func (f *Middlewares) Prepare() error { f.log = log.WithField("module", "middleware") return nil } func (f *Middlewares) Verify(c fiber.Ctx) error { // get the query parameters signature := c.Query("signature") timestamp := c.Query("timestamp") nonce := c.Query("nonce") echostr := c.Query("echostr") if signature == "" || timestamp == "" || nonce == "" || echostr == "" { return c.Next() } log.WithField("method", "Verify").WithFields(log.Fields{ "signature": signature, "timestamp": timestamp, "nonce": nonce, "echostr": echostr, }).Debug("begin verify signature") // verify the signature if err := f.client.Verify(signature, timestamp, nonce); err != nil { return c.SendString(err.Error()) } return c.SendString(echostr) } func (f *Middlewares) SilentAuth(c fiber.Ctx) error { // if cookie not exists key "openid", then redirect to the wechat auth page tokenCookie := c.Cookies("token", "") if tokenCookie != "" { claim, err := f.jwt.Parse(tokenCookie) if err != nil { return errors.Wrap(err, "failed to parse token") } // query user user, err := f.userSvc.GetByOpenID(c.Context(), claim.ID) if err != nil { return errors.Wrap(err, "failed to get user") } c.SetUserContext(context.WithValue(c.UserContext(), consts.CtxKeyJwt, tokenCookie)) c.SetUserContext(context.WithValue(c.UserContext(), consts.CtxKeySession, user)) return c.Next() } // get current full url url := c.BaseURL() url = "https://qvyun.mp.jdwan.com" log.WithField("module", "middleware.SilentAuth").Debug("url:", url) to, err := f.client.ScopeAuthorizeURL( wechat.ScopeAuthorizeURLWithRedirectURI(url), wechat.ScopeAuthorizeURLWithState("sns_basic_auth"), ) if err != nil { return errors.Wrap(err, "failed to get wechat auth url") } log.WithField("module", "middleware.SilentAuth").Debug("redirectTo: ", to.String()) return c.Redirect().To(to.String()) } func (f *Middlewares) AuthUserInfo(c fiber.Ctx) error { state := c.Query("state") code := c.Query("code") if state == "" && code == "" { return c.Next() } if state != "sns_basic_auth" { return c.Next() } log.WithField("module", "middleware.AuthUserInfo").Debug("code", code) // get the openid token, err := f.client.AuthorizeCode2Token(code) if err != nil { return errors.Wrap(err, "failed to get openid") } var oauthInfo pg.UserOAuth copier.Copy(&oauthInfo, token) user, err := f.userSvc.GetOrNew(c.Context(), 1, token.Openid, oauthInfo) if err != nil { return errors.Wrap(err, "failed to get user") } claim := f.jwt.CreateClaims(jwt.BaseClaims{UID: uint64(user.ID)}) claim.ID = user.OpenID jwtToken, err := f.jwt.CreateToken(claim) if err != nil { return errors.Wrap(err, "failed to create token") } // set the openid to the cookie c.Cookie(&fiber.Cookie{ Name: "token", Value: jwtToken, HTTPOnly: true, }) return c.Redirect().To("/") }