package http import ( "net/url" "time" "quyun/app/model" "quyun/database/fields" "quyun/pkg/utils" "quyun/providers/jwt" "quyun/providers/wechat" "github.com/gofiber/fiber/v3" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) const ( StatePrefix = "sns_basic_auth" salt = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ) // @provider type auth struct { wechat *wechat.Client jwt *jwt.JWT } // @Router /auth/login [get] // @Bind code query // @Bind state query // @Bind redirect query func (ctl *auth) Login(ctx fiber.Ctx, code, state, redirect string) error { log.Debugf("code: %s, state: %s", code, state) // get the openid token, err := ctl.wechat.AuthorizeCode2Token(code) if err != nil { return errors.Wrap(err, "failed to get openid") } log.Debugf("tokenInfo %+v", token) stableToken, err := ctl.wechat.GetStableAccessToken() if err != nil { return errors.Wrap(err, "failed to get stable access token") } log.Infof("stableToken %+v", stableToken) authUserInfo, err := ctl.wechat.AuthorizeUserInfo(token.AccessToken, token.Openid) if err != nil { log.Error("failed to get user info: ", err) authUserInfo = &wechat.AuthorizeUserInfo{ City: "", Country: "", Headimgurl: utils.RandomAvatar(), Nickname: utils.RandomNickname(), Openid: token.Openid, Privilege: []string{}, Province: "", Sex: 0, Unionid: "", } } log.Debugf("Auth User Info: %+v", authUserInfo) userModel := &model.Users{ Status: fields.UserStatusOk, OpenID: token.GetOpenID(), // Username: fmt.Sprintf("u_%s", gonanoid.MustGenerate(salt, 8)), Username: authUserInfo.Nickname, Avatar: &authUserInfo.Headimgurl, Metas: fields.ToJson(fields.UserMetas{ City: authUserInfo.City, Country: authUserInfo.Country, HeadImageUrl: authUserInfo.Headimgurl, Nickname: authUserInfo.Nickname, Privilege: authUserInfo.Privilege, Province: authUserInfo.Province, Sex: authUserInfo.Sex, }), AuthToken: fields.ToJson(fields.UserAuthToken{ StableAccessToken: stableToken.AccessToken, StableExpiresAt: time.Now().Add(time.Second * time.Duration(stableToken.ExpiresIn)), AccessToken: token.AccessToken, ExpiresAt: time.Now().Add(time.Second * time.Duration(token.ExpiresIn)), IsSnapshotuser: token.IsSnapshotuser, RefreshToken: token.RefreshToken, Scope: token.Scope, }), } user, err := model.UsersModel().GetUserByOpenIDOrCreate(ctx.Context(), token.GetOpenID(), userModel) if err != nil { return errors.Wrap(err, "failed to get user by openid") } jwtToken, err := ctl.jwt.CreateToken(ctl.jwt.CreateClaims(jwt.BaseClaims{UserID: user.ID})) if err != nil { return errors.Wrap(err, "failed to create token") } ctx.Cookie(&fiber.Cookie{ Name: "token", Value: jwtToken, Expires: time.Now().Add(24 * time.Hour), HTTPOnly: true, }) return ctx.Redirect().To(redirect) } // @Router /auth/wechat [get] // @Bind redirect query func (ctl *auth) Wechat(ctx fiber.Ctx, redirect string) error { log.Debugf("%s, query: %v", ctx.OriginalURL(), ctx.Queries()) // 添加 redirect 参数 fullUrl := utils.FullURI(ctx) u, err := url.Parse(fullUrl) if err != nil { return err } query := u.Query() query.Set("redirect", redirect) u.RawQuery = query.Encode() u.Path = "/v1/auth/login" fullUrl = u.String() log.Debug("redirect_uri: ", fullUrl) to, err := ctl.wechat.ScopeAuthorizeURL( wechat.ScopeAuthorizeURLWithRedirectURI(fullUrl), ) if err != nil { return errors.Wrap(err, "failed to get wechat auth url") } return ctx.Redirect().To(to.String()) }