diff --git a/backend/app/http/auth/controller_wechat.go b/backend/app/http/auth/controller_wechat.go index 6a6fe28..c154485 100644 --- a/backend/app/http/auth/controller_wechat.go +++ b/backend/app/http/auth/controller_wechat.go @@ -100,3 +100,14 @@ func (ctl *Controller) Login(ctx fiber.Ctx, code, state, redirectUri string) err return ctx.Redirect().To(redirectUri) } + +// @Router /MP_verify_:uuid.txt [get] +// @Bind uuid path +func (ctl *Controller) Verify(ctx fiber.Ctx, uuid string) error { + v, err := ctl.wechat.VerifySite(uuid) + if err != nil { + return err + } + + return ctx.SendString(v) +} diff --git a/backend/app/http/auth/routes.gen.go b/backend/app/http/auth/routes.gen.go index d4cc5a8..e2f6a32 100644 --- a/backend/app/http/auth/routes.gen.go +++ b/backend/app/http/auth/routes.gen.go @@ -40,4 +40,9 @@ func (r *Routes) Register(router fiber.Router) { QueryParam[string]("redirectUri"), )) + router.Get("/MP_verify_:uuid.txt", Func1( + r.controller.Verify, + PathParam[string]("uuid"), + )) + } diff --git a/backend/app/http/tenants/controller.go b/backend/app/http/tenants/controller.go index 74d126b..d98f610 100644 --- a/backend/app/http/tenants/controller.go +++ b/backend/app/http/tenants/controller.go @@ -1,6 +1,9 @@ package tenants import ( + "time" + + "backend/app/consts" "backend/providers/jwt" "backend/providers/otel" @@ -11,6 +14,7 @@ import ( // @provider type Controller struct { svc *Service + jwt *jwt.JWT log *log.Entry `inject:"false"` } @@ -36,6 +40,21 @@ func (c *Controller) Index(ctx fiber.Ctx, tenant string, claim *jwt.Claims) erro return err } + if claim.TenantID == nil { + claim.TenantID = &tenantModel.ID + token, err := c.jwt.CreateToken(claim) + if err != nil { + return err + } + + ctx.Cookie(&fiber.Cookie{ + Name: consts.TokenTypeUser.String(), + Value: token, + Expires: time.Now().Add(6 * time.Hour), + HTTPOnly: true, + }) + } + // TODO: render page return nil } diff --git a/backend/app/http/tenants/provider.gen.go b/backend/app/http/tenants/provider.gen.go index bade9d4..0d17296 100755 --- a/backend/app/http/tenants/provider.gen.go +++ b/backend/app/http/tenants/provider.gen.go @@ -3,6 +3,8 @@ package tenants import ( "database/sql" + "backend/providers/jwt" + "git.ipao.vip/rogeecn/atom" "git.ipao.vip/rogeecn/atom/container" "git.ipao.vip/rogeecn/atom/contracts" @@ -11,9 +13,11 @@ import ( func Provide(opts ...opt.Option) error { if err := container.Container.Provide(func( + jwt *jwt.JWT, svc *Service, ) (*Controller, error) { obj := &Controller{ + jwt: jwt, svc: svc, } if err := obj.Prepare(); err != nil { diff --git a/backend/app/middlewares/m_check_ua.go b/backend/app/middlewares/m_check_ua.go index 88a5f05..8f9a14a 100644 --- a/backend/app/middlewares/m_check_ua.go +++ b/backend/app/middlewares/m_check_ua.go @@ -7,10 +7,14 @@ import ( ) func (m *Middlewares) CheckUA(ctx fiber.Ctx) error { + if m.app.IsDevMode() { + return ctx.Next() + } + keyword := strings.ToLower("MicroMessenger") userAgent := ctx.GetReqHeaders()["User-Agent"][0] - if strings.Contains(userAgent, keyword) { + if !strings.Contains(userAgent, keyword) { return ctx.SendString("") } return ctx.Next() diff --git a/backend/app/middlewares/m_jwt_parse.go b/backend/app/middlewares/m_jwt_parse.go index 3c51efd..1d73e54 100644 --- a/backend/app/middlewares/m_jwt_parse.go +++ b/backend/app/middlewares/m_jwt_parse.go @@ -1,37 +1,27 @@ package middlewares import ( - "time" - + "backend/app/consts" "backend/app/errorx" "github.com/gofiber/fiber/v3" - log "github.com/sirupsen/logrus" ) func (f *Middlewares) ParseJWT(c fiber.Ctx) error { - tokens := c.GetReqHeaders()["Authorization"] - if len(tokens) == 0 { - queryToken := c.Query("token") - tokens = []string{queryToken} - if len(tokens) == 0 { + token := c.Cookies(consts.TokenTypeUser.String()) + if token == "" { + token = c.Query("token") + if token == "" { return c.Next() } } - token := tokens[0] claim, err := f.jwt.Parse(token) if err != nil { - c.Cookie(&fiber.Cookie{ - Name: "token", - Value: "", - Expires: time.Now().Add(-1 * time.Hour), - HTTPOnly: true, - }) - log.Errorf("failed to parse jwt from token: %s", token) + c.ClearCookie(consts.TokenTypeUser.String()) return errorx.Unauthorized } - _ = claim + c.Locals("claim", claim) return c.Next() } diff --git a/backend/app/middlewares/m_wechat_auth.go b/backend/app/middlewares/m_wechat_auth.go deleted file mode 100644 index cfe8a31..0000000 --- a/backend/app/middlewares/m_wechat_auth.go +++ /dev/null @@ -1,66 +0,0 @@ -package middlewares - -import ( - "fmt" - "strings" - "time" - - "backend/providers/wechat" - - "github.com/gofiber/fiber/v3" - "github.com/pkg/errors" - log "github.com/sirupsen/logrus" -) - -const StatePrefix = "sns_basic_auth" - -func (f *Middlewares) WeChatAuth(c fiber.Ctx) error { - log := log.WithField("module", "middleware.AuthUserInfo") - log.Debugf("%s, query: %v", c.OriginalURL(), c.Queries()) - state := c.Query("state") - code := c.Query("code") - log.Debugf("code: %s, state: %s", code, state) - - jwtToken := c.Cookies("token") - if jwtToken != "" { - log.Debugf("jwtToken: %s", jwtToken) - - if _, err := f.jwt.Parse(jwtToken); err != nil { - log.WithError(err).Error("failed to parse jwt token") - - c.Cookie(&fiber.Cookie{ - Name: "token", - Value: "", - Expires: time.Now().Add(-1 * time.Hour), - HTTPOnly: true, - }) - return c.Redirect().To(c.Path()) - } - } - - if state == "" && code == "" { - url := string(c.Request().URI().FullURI()) - url = strings.ReplaceAll(url, "http", "https") - url = strings.ReplaceAll(url, c.BaseURL(), *f.app.BaseURI) - - log.WithField("module", "middleware.SilentAuth").Debug("redirect_uri: ", url) - - to, err := f.client.ScopeAuthorizeURL( - wechat.ScopeAuthorizeURLWithRedirectURI(url), - wechat.ScopeAuthorizeURLWithState(fmt.Sprintf("%s_%d", StatePrefix, time.Now().UnixNano())), - ) - 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()) - - } - - if !strings.HasPrefix(state, StatePrefix) || code == "" { - return errors.New("invalid request") - } - - return c.Next() -} diff --git a/backend/app/service/http/http.go b/backend/app/service/http/http.go index c989ca3..a6b2533 100644 --- a/backend/app/service/http/http.go +++ b/backend/app/service/http/http.go @@ -2,11 +2,13 @@ package http import ( "backend/app/errorx" + "backend/app/events/subscribers" "backend/app/jobs" "backend/app/middlewares" "backend/app/service" _ "backend/docs" "backend/providers/app" + "backend/providers/event" "backend/providers/hashids" "backend/providers/http" "backend/providers/http/swagger" @@ -17,7 +19,6 @@ import ( "git.ipao.vip/rogeecn/atom" "git.ipao.vip/rogeecn/atom/container" "git.ipao.vip/rogeecn/atom/contracts" - "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/middleware/favicon" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -31,6 +32,7 @@ func defaultProviders() container.Providers { jwt.DefaultProvider(), hashids.DefaultProvider(), job.DefaultProvider(), + event.DefaultProvider(), }...) } @@ -43,6 +45,7 @@ func Command() atom.Option { defaultProviders(). With( jobs.Provide, + subscribers.Provide, ), ), ) @@ -70,16 +73,15 @@ func Serve(cmd *cobra.Command, args []string) error { svc.Http.Engine.Get("/swagger/*", swagger.HandlerDefault) } - svc.Http.Engine.Get("MP_verify_dEF9kn8rJlBsuLKk.txt", func(c fiber.Ctx) error { - return c.SendString("dEF9kn8rJlBsuLKk") - }) - - svc.Http.Engine.Use(svc.Middlewares.WeChatVerify) + // core svc.Http.Engine.Use(errorx.Middleware) svc.Http.Engine.Use(favicon.New(favicon.Config{ Data: []byte{}, })) + svc.Http.Engine.Use(svc.Middlewares.WeChatVerify) + svc.Http.Engine.Use(svc.Middlewares.CheckUA) + group := svc.Http.Engine.Group("") for _, route := range svc.Routes { route.Register(group) diff --git a/backend/app/service/service.go b/backend/app/service/service.go index 32f775b..d03fd84 100644 --- a/backend/app/service/service.go +++ b/backend/app/service/service.go @@ -2,7 +2,6 @@ package service import ( "backend/providers/app" - "backend/providers/event" "git.ipao.vip/rogeecn/atom/container" ) @@ -10,6 +9,5 @@ import ( func Default(providers ...container.ProviderContainer) container.Providers { return append(container.Providers{ app.DefaultProvider(), - event.DefaultProvider(), }, providers...) } diff --git a/backend/pkg/f/func.go b/backend/pkg/f/func.go index cee78bb..b6a5dfe 100644 --- a/backend/pkg/f/func.go +++ b/backend/pkg/f/func.go @@ -4,6 +4,8 @@ import ( "github.com/gofiber/fiber/v3" ) +var Func0 = Func + func Func(f fiber.Handler) fiber.Handler { return f } diff --git a/backend/providers/wechat/options.go b/backend/providers/wechat/options.go index fbf74eb..68b0e01 100644 --- a/backend/providers/wechat/options.go +++ b/backend/providers/wechat/options.go @@ -67,3 +67,10 @@ func ScopeAuthorizeURLWithForcePopup() ScopeAuthorizeURLOptions { v.Set("forcePopup", "true") } } + +func WithVerifySiteKeyPair(key, value string) Options { + return func(we *Client) { + we.verifyKey = key + we.verifyValue = value + } +} diff --git a/backend/providers/wechat/provider.go b/backend/providers/wechat/provider.go index 3bc297d..88704c9 100644 --- a/backend/providers/wechat/provider.go +++ b/backend/providers/wechat/provider.go @@ -22,6 +22,10 @@ type Config struct { Token string AesKey string DevMode bool + Verify struct { + Key string + Value string + } } func Provide(opts ...opt.Option) error { @@ -42,6 +46,7 @@ func Provide(opts ...opt.Option) error { WithAESKey(config.AesKey), WithToken(config.Token), WithClient(httpClient), + WithVerifySiteKeyPair(config.Verify.Key, config.Verify.Value), ), nil }, o.DiOptions()...) } diff --git a/backend/providers/wechat/wechat.go b/backend/providers/wechat/wechat.go index d26b404..9139091 100644 --- a/backend/providers/wechat/wechat.go +++ b/backend/providers/wechat/wechat.go @@ -39,6 +39,9 @@ type Client struct { appSecret string token string aesKey string + + verifyKey string + verifyValue string } func New(options ...Options) *Client { @@ -53,6 +56,13 @@ func New(options ...Options) *Client { return we } +func (we *Client) VerifySite(key string) (string, error) { + if key == we.verifyKey { + return we.verifyValue, nil + } + return "", errors.New("verify failed") +} + func (we *Client) Verify(signature, timestamp, nonce string) error { params := []string{signature, timestamp, nonce, we.token} sort.Strings(params)