feat: add middlewares

This commit is contained in:
Rogee
2024-12-06 17:15:28 +08:00
parent 29894cff9c
commit 869625d70a
10 changed files with 169 additions and 125 deletions

View File

@@ -61,9 +61,9 @@ type Http struct {
func Serve(cmd *cobra.Command, args []string) error { func Serve(cmd *cobra.Command, args []string) error {
return container.Container.Invoke(func(http Http) error { return container.Container.Invoke(func(http Http) error {
mid := http.Middlewares mid := http.Middlewares
http.Service.Engine.Use(mid.Verify) http.Service.Engine.Use(mid.WeChatVerify)
http.Service.Engine.Use(mid.AuthUserInfo) http.Service.Engine.Use(mid.AuthUserInfo)
http.Service.Engine.Use(mid.SilentAuth) http.Service.Engine.Use(mid.WeChatSilentAuth)
mounts := map[string][]string{ mounts := map[string][]string{
"/t/{tenant}": {"users", "medias"}, "/t/{tenant}": {"users", "medias"},

View File

@@ -3,6 +3,7 @@ Mode = "development"
[Http] [Http]
Port = 9800 Port = 9800
BaseURI = "https://qvyun.mp.jdwan.com"
[Swagger] [Swagger]
BaseRoute = "doc" BaseRoute = "doc"

View File

@@ -0,0 +1,34 @@
package middlewares
import (
"context"
"backend/common/consts"
"github.com/gofiber/fiber/v3"
"github.com/pkg/errors"
)
func (f *Middlewares) JwtParse(c fiber.Ctx) error {
tokens := c.GetReqHeaders()["Authorization"]
if len(tokens) == 0 {
return c.Next()
}
token := tokens[0]
claim, err := f.jwt.Parse(token)
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, token))
c.SetUserContext(context.WithValue(c.UserContext(), consts.CtxKeySession, user))
return c.Next()
}

View File

@@ -0,0 +1,33 @@
package middlewares
import (
"backend/providers/wechat"
"github.com/gofiber/fiber/v3"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
func (f *Middlewares) WeChatSilentAuth(c fiber.Ctx) error {
// if cookie not exists key "openid", then redirect to the wechat auth page
token := c.GetReqHeaders()["Authorization"]
if len(token) != 0 {
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())
}

View File

@@ -0,0 +1,33 @@
package middlewares
import (
"github.com/gofiber/fiber/v3"
log "github.com/sirupsen/logrus"
)
// 此方法用于微信首次接入时的数据验证
func (f *Middlewares) WeChatVerify(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)
}

View File

@@ -0,0 +1,54 @@
package middlewares
import (
"backend/pkg/pg"
"backend/providers/jwt"
"github.com/gofiber/fiber/v3"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
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("/")
}

View File

@@ -0,0 +1,9 @@
package middlewares
import (
"github.com/gofiber/fiber/v3"
)
func (f *Middlewares) DebugMode(c fiber.Ctx) error {
return c.Next()
}

View File

@@ -1,17 +1,10 @@
package middlewares package middlewares
import ( import (
"context"
"backend/common/consts"
"backend/modules/users" "backend/modules/users"
"backend/pkg/pg"
"backend/providers/jwt" "backend/providers/jwt"
"backend/providers/wechat" "backend/providers/wechat"
"github.com/gofiber/fiber/v3"
"github.com/jinzhu/copier"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@@ -27,110 +20,3 @@ func (f *Middlewares) Prepare() error {
f.log = log.WithField("module", "middleware") f.log = log.WithField("module", "middleware")
return nil 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("/")
}

View File

@@ -9,7 +9,7 @@ const DefaultPrefix = "Http"
type Config struct { type Config struct {
StaticPath *string StaticPath *string
StaticRoute *string StaticRoute *string
Host *string BaseURI *string
Port uint Port uint
Tls *Tls Tls *Tls
Cors *Cors Cors *Cors
@@ -34,12 +34,5 @@ type Whitelist struct {
} }
func (h *Config) Address() string { func (h *Config) Address() string {
if h.Host == nil {
return h.PortString()
}
return fmt.Sprintf("%s:%d", *h.Host, h.Port)
}
func (h *Config) PortString() string {
return fmt.Sprintf(":%d", h.Port) return fmt.Sprintf(":%d", h.Port)
} }

View File

@@ -38,6 +38,7 @@ func (svc *Service) Serve() error {
OnShutdownError: func(err error) { OnShutdownError: func(err error) {
log.Error("http server shutdown error: ", err) log.Error("http server shutdown error: ", err)
}, },
// DisableStartupMessage: true, // DisableStartupMessage: true,
} }
@@ -52,7 +53,7 @@ func (svc *Service) Serve() error {
svc.Engine.Shutdown() svc.Engine.Shutdown()
}) })
return svc.Engine.Listen(svc.conf.PortString(), listenConfig) return svc.Engine.Listen(svc.conf.Address(), listenConfig)
} }
func Provide(opts ...opt.Option) error { func Provide(opts ...opt.Option) error {