diff --git a/backend/.air.toml b/backend/.air.toml new file mode 100644 index 0000000..649a464 --- /dev/null +++ b/backend/.air.toml @@ -0,0 +1,52 @@ +root = "." +testdata_dir = "testdata" +tmp_dir = "tmp" + +[build] + args_bin = ["serve"] + bin = "./tmp/main" + cmd = "go build -o ./tmp/main ." + delay = 1000 + exclude_dir = ["assets", "tmp", "vendor", "testdata"] + exclude_file = [] + exclude_regex = ["_test.go"] + exclude_unchanged = false + follow_symlink = false + full_bin = "" + include_dir = [] + include_ext = ["go", "tpl", "tmpl", "html"] + include_file = [] + kill_delay = "0s" + log = "build-errors.log" + poll = false + poll_interval = 0 + post_cmd = [] + pre_cmd = [] + rerun = false + rerun_delay = 500 + send_interrupt = false + stop_on_error = false + +[color] + app = "" + build = "yellow" + main = "magenta" + runner = "green" + watcher = "cyan" + +[log] + main_only = false + silent = false + time = false + +[misc] + clean_on_exit = false + +[proxy] + app_port = 0 + enabled = false + proxy_port = 0 + +[screen] + clear_on_rebuild = false + keep_scroll = true diff --git a/backend/__debug_bin1551459525 b/backend/__debug_bin1551459525 deleted file mode 100755 index 80e6378..0000000 Binary files a/backend/__debug_bin1551459525 and /dev/null differ diff --git a/backend/common/service/http/http.go b/backend/common/service/http/http.go index e3a981a..433b22f 100644 --- a/backend/common/service/http/http.go +++ b/backend/common/service/http/http.go @@ -14,9 +14,7 @@ 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/log" - "github.com/samber/lo" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "go.uber.org/dig" ) @@ -31,20 +29,17 @@ func defaultProviders(providers ...container.ProviderContainer) container.Provid } func Command() atom.Option { - providers := defaultProviders( - wechat.DefaultProvider(), - storage.DefaultProvider(), - ).With( - users.Provide, - medias.Provide, - ) - return atom.Command( atom.Name("serve"), atom.Short("run http server"), atom.RunE(Serve), - atom.Providers(providers.With( + atom.Providers(defaultProviders( + storage.DefaultProvider(), + wechat.DefaultProvider(), + ).With( middlewares.Provide, + users.Provide, + medias.Provide, )), ) } @@ -52,6 +47,7 @@ func Command() atom.Option { type Http struct { dig.In + App *app.Config Service *http.Service Initials []contracts.Initial `group:"initials"` Routes []contracts.HttpRoute `group:"routes"` @@ -60,34 +56,20 @@ type Http struct { func Serve(cmd *cobra.Command, args []string) error { return container.Container.Invoke(func(http Http) error { + if http.App.Mode == app.AppModeDevelopment { + log.SetLevel(log.DebugLevel) + } + mid := http.Middlewares + http.Service.Engine.Use(mid.DebugMode) http.Service.Engine.Use(mid.WeChatVerify) http.Service.Engine.Use(mid.WeChatAuthUserInfo) http.Service.Engine.Use(mid.WeChatSilentAuth) http.Service.Engine.Use(mid.ParseJWT) - mounts := map[string][]string{ - "/t/{tenant}": {"users", "medias"}, - } + group := http.Service.Engine.Group("/v1") for _, route := range http.Routes { - r := route.Register() - if app, ok := r.(*fiber.App); ok { - match := false - for prefix, groups := range mounts { - log.Infof("mount %s to %s", prefix, route.Name()) - if lo.Contains(groups, route.Name()) { - match = true - http.Service.Engine.Use(prefix, app) - break - } - } - _ = match - - if !match { - log.Infof("mount / to %s", route.Name()) - http.Service.Engine.Use(app) - } - } + route.Register(group) } return http.Service.Serve() diff --git a/backend/config.toml b/backend/config.toml index 1a4f501..90d2485 100755 --- a/backend/config.toml +++ b/backend/config.toml @@ -1,9 +1,9 @@ [App] Mode = "development" +BaseURI = "https://qvyun.mp.jdwan.com" [Http] -Port = 9800 -BaseURI = "https://qvyun.mp.jdwan.com" +Port = 3000 [Swagger] BaseRoute = "doc" diff --git a/backend/modules/medias/router.go b/backend/modules/medias/router.go index c71c125..125e67a 100755 --- a/backend/modules/medias/router.go +++ b/backend/modules/medias/router.go @@ -9,9 +9,7 @@ import ( // @provider:except contracts.HttpRoute atom.GroupRoutes type Router struct { - app *fiber.App `inject:"false"` - group fiber.Router `inject:"false"` - log *log.Entry `inject:"false"` + log *log.Entry `inject:"false"` controller *Controller } @@ -22,14 +20,10 @@ func (r *Router) Name() string { func (r *Router) Prepare() error { r.log = log.WithField("http.group", r.Name()) - r.app = fiber.New() - r.group = r.app.Group(r.Name()) - return nil } -func (r *Router) Register() any { - r.group.Get("", r.controller.List) - - return r.app +func (r *Router) Register(router fiber.Router) { + group := router.Group(r.Name()) + group.Get("", r.controller.List) } diff --git a/backend/modules/middlewares/m_jwt_parse.go b/backend/modules/middlewares/m_jwt_parse.go index 7e5d053..db86929 100644 --- a/backend/modules/middlewares/m_jwt_parse.go +++ b/backend/modules/middlewares/m_jwt_parse.go @@ -20,17 +20,15 @@ func (f *Middlewares) ParseJWT(c fiber.Ctx) error { } // query user - user, err := f.userSvc.GetByOpenID(c.Context(), claim.OpenID) + _, err = f.userSvc.GetByOpenID(c.Context(), claim.OpenID) if err != nil { return errors.Wrap(err, "failed to get user") } - claim.UserID = user.ID - tenantId, err := f.userSvc.GetTenantIDBySlug(c.Context(), claim.Tenant) + _, err = f.userSvc.GetTenantBySlug(c.Context(), claim.Tenant) if err != nil { return errors.Wrap(err, "failed to get tenant") } - claim.TenantID = tenantId c.Locals(consts.CtxKeyJwt, token) c.Locals(consts.CtxKeyClaim, claim) diff --git a/backend/modules/middlewares/m_wechat_auth_userinfo.go b/backend/modules/middlewares/m_wechat_auth_userinfo.go index ce8034d..3e549d9 100644 --- a/backend/modules/middlewares/m_wechat_auth_userinfo.go +++ b/backend/modules/middlewares/m_wechat_auth_userinfo.go @@ -1,16 +1,20 @@ package middlewares import ( + "strings" + "backend/pkg/pg" "backend/providers/jwt" "github.com/gofiber/fiber/v3" "github.com/jinzhu/copier" "github.com/pkg/errors" + "github.com/samber/lo" log "github.com/sirupsen/logrus" ) func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error { + // 如果请求存在 Authorization 头,则跳过 if len(c.GetReqHeaders()["Authorization"]) != 0 { return c.Next() } @@ -33,12 +37,19 @@ func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error { return errors.Wrap(err, "failed to get openid") } - tenantSlug := c.Path("tenant") + paths := lo.Filter(strings.Split(c.Path(), "/"), func(s string, _ int) bool { + return s != "" + }) + if len(paths) < 2 || paths[0] != "t" { + return errors.New("invalid path") + } + + tenantSlug := paths[1] if tenantSlug == "" { return errors.New("tenant is empty") } - tenantId, err := f.userSvc.GetTenantIDBySlug(c.Context(), tenantSlug) + tenant, err := f.userSvc.GetTenantBySlug(c.Context(), tenantSlug) if err != nil { return errors.Wrap(err, "failed to get tenant id") } @@ -48,7 +59,7 @@ func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error { return errors.Wrap(err, "failed to copy oauth info") } - user, err := f.userSvc.GetOrNew(c.Context(), tenantId, token.Openid, oauthInfo) + user, err := f.userSvc.GetOrNew(c.Context(), tenant.ID, token.Openid, oauthInfo) if err != nil { return errors.Wrap(err, "failed to get user") } @@ -61,5 +72,6 @@ func (f *Middlewares) WeChatAuthUserInfo(c fiber.Ctx) error { } _ = jwtToken - return c.Redirect().To("/") + // TODO: send html with jwt token + return c.SendString("Tenant: " + tenantSlug) } diff --git a/backend/modules/middlewares/m_wechat_silent_auth.go b/backend/modules/middlewares/m_wechat_silent_auth.go index d4857c9..60d2125 100644 --- a/backend/modules/middlewares/m_wechat_silent_auth.go +++ b/backend/modules/middlewares/m_wechat_silent_auth.go @@ -1,6 +1,8 @@ package middlewares import ( + "strings" + "backend/providers/wechat" "github.com/gofiber/fiber/v3" @@ -16,8 +18,12 @@ func (f *Middlewares) WeChatSilentAuth(c fiber.Ctx) error { } // get current full url - url := c.BaseURL() - url = "https://qvyun.mp.jdwan.com" + url := string(c.Request().URI().FullURI()) + if f.app.IsDevMode() && f.app.BaseURI != nil { + url = strings.ReplaceAll(url, "http", "https") + url = strings.ReplaceAll(url, c.BaseURL(), *f.app.BaseURI) + } + log.WithField("module", "middleware.SilentAuth").Debug("url:", url) to, err := f.client.ScopeAuthorizeURL( diff --git a/backend/modules/middlewares/mid_debug.go b/backend/modules/middlewares/mid_debug.go index ecb33af..92716b1 100644 --- a/backend/modules/middlewares/mid_debug.go +++ b/backend/modules/middlewares/mid_debug.go @@ -5,5 +5,9 @@ import ( ) func (f *Middlewares) DebugMode(c fiber.Ctx) error { + // fullURI := c.Request().URI().FullURI() + // host := c.BaseURL() + // fmt.Println(strings.Split(c.Path(), "/")) + // return c.SendString(c.Params("tenant", "no tenant: "+c.Path())) return c.Next() } diff --git a/backend/modules/middlewares/middlewares.go b/backend/modules/middlewares/middlewares.go index 8f3fc5c..4f7f026 100644 --- a/backend/modules/middlewares/middlewares.go +++ b/backend/modules/middlewares/middlewares.go @@ -2,6 +2,7 @@ package middlewares import ( "backend/modules/users" + "backend/providers/app" "backend/providers/jwt" "backend/providers/wechat" @@ -10,6 +11,7 @@ import ( // @provider type Middlewares struct { + app *app.Config client *wechat.Client userSvc *users.Service jwt *jwt.JWT diff --git a/backend/modules/middlewares/provider.gen.go b/backend/modules/middlewares/provider.gen.go index bc349dc..58001f2 100755 --- a/backend/modules/middlewares/provider.gen.go +++ b/backend/modules/middlewares/provider.gen.go @@ -2,6 +2,7 @@ package middlewares import ( "backend/modules/users" + "backend/providers/app" "backend/providers/jwt" "backend/providers/wechat" @@ -11,11 +12,13 @@ import ( func Provide(opts ...opt.Option) error { if err := container.Container.Provide(func( + app *app.Config, client *wechat.Client, jwt *jwt.JWT, userSvc *users.Service, ) (*Middlewares, error) { obj := &Middlewares{ + app: app, client: client, jwt: jwt, userSvc: userSvc, diff --git a/backend/modules/users/controller.go b/backend/modules/users/controller.go index 3dc85d5..dbe6582 100644 --- a/backend/modules/users/controller.go +++ b/backend/modules/users/controller.go @@ -9,5 +9,6 @@ type Controller struct { // List func (c *Controller) List(ctx fiber.Ctx) error { + return ctx.SendString(ctx.Params("tenant", "no tenant")) return ctx.JSON(nil) } diff --git a/backend/modules/users/router.go b/backend/modules/users/router.go index 2ef0b16..58c7821 100755 --- a/backend/modules/users/router.go +++ b/backend/modules/users/router.go @@ -9,17 +9,13 @@ import ( // @provider:except contracts.HttpRoute atom.GroupRoutes type Router struct { - app *fiber.App `inject:"false"` - group fiber.Router `inject:"false"` - log *log.Entry `inject:"false"` + log *log.Entry `inject:"false"` controller *Controller } func (r *Router) Prepare() error { r.log = log.WithField("http.group", r.Name()) - r.app = fiber.New() - r.group = r.app.Group(r.Name()) return nil } @@ -28,8 +24,7 @@ func (r *Router) Name() string { return "users" } -func (r *Router) Register() any { - r.group.Get("", r.controller.List) - - return r.app +func (r *Router) Register(router fiber.Router) { + group := router.Group(r.Name()) + group.Get("", r.controller.List) } diff --git a/backend/modules/users/service.go b/backend/modules/users/service.go index a7f65e1..36aee45 100644 --- a/backend/modules/users/service.go +++ b/backend/modules/users/service.go @@ -66,6 +66,10 @@ func (svc *Service) GetByOpenID(ctx context.Context, openid string) (*model.User func (svc *Service) GetOrNew(ctx context.Context, tenantID int64, openid string, authInfo pg.UserOAuth) (*model.Users, error) { log := svc.log.WithField("method", "GetOrNew") + svc.log.Infof("get or new user for tenant: %d, openid: %s", tenantID, openid) + if openid == "" { + return nil, errors.New("openid is empty") + } user, err := svc.GetByOpenID(ctx, openid) if err == nil { // check: if tenant has user @@ -196,17 +200,17 @@ func (svc *Service) CreateTenantUser(ctx context.Context, userID, tenantID int64 } // GetTenantIDBySlug -func (svc *Service) GetTenantIDBySlug(ctx context.Context, slug string) (int64, error) { +func (svc *Service) GetTenantBySlug(ctx context.Context, slug string) (*model.Tenants, error) { log := svc.log.WithField("method", "GetTenantIDBySlug") - stmt := table.Tenants.SELECT(table.Tenants.ID).WHERE(table.Tenants.Slug.EQ(String(slug))) + stmt := table.Tenants.SELECT(table.Tenants.AllColumns).WHERE(table.Tenants.Slug.EQ(String(slug))) log.Debug(stmt.DebugSql()) - var id int64 - if err := stmt.QueryContext(ctx, db.FromContext(ctx, svc.db), &id); err != nil { - return 0, errors.Wrap(err, "failed to query tenant id by slug") + var item model.Tenants + if err := stmt.QueryContext(ctx, db.FromContext(ctx, svc.db), &item); err != nil { + return nil, errors.Wrap(err, "failed to query tenant id by slug") } - return id, nil + return &item, nil } // CreateTenant diff --git a/backend/providers/wechat/provider.go b/backend/providers/wechat/provider.go index a0d9c92..3bc297d 100644 --- a/backend/providers/wechat/provider.go +++ b/backend/providers/wechat/provider.go @@ -5,10 +5,14 @@ import ( "git.ipao.vip/rogeecn/atom/utils/opt" ) +const DefaultPrefix = "Wechat" + func DefaultProvider() container.ProviderContainer { return container.ProviderContainer{ Provider: Provide, - Options: []opt.Option{}, + Options: []opt.Option{ + opt.Prefix(DefaultPrefix), + }, } }