Files
qvyun/backend/app/http/auth/controller_wechat.go
2025-01-10 11:42:12 +08:00

121 lines
2.9 KiB
Go

package auth
import (
"fmt"
"net/url"
"strings"
"time"
"backend/app/consts"
"backend/app/http/users"
"backend/providers/jwt"
"backend/providers/otel"
"backend/providers/wechat"
"github.com/gofiber/fiber/v3"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
const StatePrefix = "sns_basic_auth"
// @provider
type Controller struct {
svc *Service
userSvc *users.Service
jwt *jwt.JWT
wechat *wechat.Client
log *log.Entry `inject:"false"`
}
func (ctl *Controller) Prepare() error {
ctl.log = log.WithField("module", "auth.Controller")
return nil
}
// @Router /v1/auth/wechat/jump/:tenant [get]
// @Bind tenant path
// @Bind redirectUri query
func (ctl *Controller) JumpToAuth(ctx fiber.Ctx, tenant, redirectUri string) error {
_, span := otel.Start(ctx.Context(), "auth.controller.wechat")
defer span.End()
ctl.log.Debugf("%s, query: %v", ctx.OriginalURL(), ctx.Queries())
paramRedirect := ctx.Query("redirect")
// 添加 redirect 参数
u, err := url.Parse(string(ctx.Request().URI().FullURI()))
if err != nil {
return err
}
query := u.Query()
query.Set("redirect", paramRedirect)
u.RawQuery = query.Encode()
u.Path = "/v1/auth/wechat/login/" + tenant
fullUrl := u.String()
ctl.log.WithField("module", "middleware.SilentAuth").Debug("redirect_uri: ", fullUrl)
to, err := ctl.wechat.ScopeAuthorizeURL(
wechat.ScopeAuthorizeURLWithRedirectURI(fullUrl),
wechat.ScopeAuthorizeURLWithState(fmt.Sprintf("%s-%d", StatePrefix, time.Now().UnixNano())),
)
if err != nil {
return errors.Wrap(err, "failed to get wechat auth url")
}
return ctx.Redirect().To(to.String())
}
// @Router /v1/auth/login/:tenant [get]
// @Bind tenant path
// @Bind code query
// @Bind state query
// @Bind redirectUri query
func (ctl *Controller) Login(ctx fiber.Ctx, code, state, tenant, redirectUri string) error {
ctl.log.Debugf("code: %s, state: %s", code, state)
ctx.Cookie(&fiber.Cookie{
Name: consts.TokenTypeUser.String(),
Value: "",
Expires: time.Now().Add(12 * time.Hour),
HTTPOnly: true,
})
// get the openid
token, err := ctl.wechat.AuthorizeCode2Token(code)
if err != nil {
return errors.Wrap(err, "failed to get openid")
}
ctl.log.Debugf("tokenInfo %+v", token)
user, err := ctl.userSvc.GetOrNewFromChannel(ctx.Context(), consts.AuthChannelWeChat, token.OpenID, tenant)
if err != nil {
return errors.Wrap(err, "failed to get user")
}
claim := c.jwt.CreateClaims(jwt.BaseClaims{
OpenID: user.OpenID,
Tenant: tenantSlug,
UserID: user.ID,
TenantID: tenant.ID,
})
jwtToken, err = c.jwt.CreateToken(claim)
if err != nil {
return errors.Wrap(err, "failed to create token")
}
ctx.Cookie(&fiber.Cookie{
Name: "token",
Value: jwtToken,
Expires: time.Now().Add(6 * time.Hour),
HTTPOnly: true,
})
html := strings.ReplaceAll(string(b), "{{JWT}}", jwtToken)
return ctx.SendString(html)
return ctx.Redirect().To(paramRedirect)
}