package logic import ( "crypto/rand" "encoding/base64" "fmt" "fusenapi/utils/auth" "fusenapi/utils/basic" "io" "log" "net/http" "time" "context" "fusenapi/server/auth/internal/svc" "fusenapi/server/auth/internal/types" "github.com/474420502/requests" "github.com/google/uuid" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/rest/httpx" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "gorm.io/gorm" ) type UserGoogleLoginLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext token string // 登录 token isRegistered bool // 是否注册 registerToken string // 注册邮箱的token registerInfo *auth.RegisterToken } func NewUserGoogleLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserGoogleLoginLogic { return &UserGoogleLoginLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // 处理进入前逻辑w,r // func (l *UserGoogleLoginLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { // } func (l *UserGoogleLoginLogic) UserGoogleLogin(req *types.RequestGoogleLogin, userinfo *auth.UserInfo) (resp *basic.Response) { // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // userinfo 传入值时, 一定不为null var googleOauthConfig = &oauth2.Config{ RedirectURL: fmt.Sprintf("http://%s/api/user/oauth2/login/google", l.svcCtx.Config.MainAddress), ClientID: l.svcCtx.Config.OAuth.Google.Appid, ClientSecret: l.svcCtx.Config.OAuth.Google.Secret, Scopes: []string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"}, Endpoint: google.Endpoint, } token, err := googleOauthConfig.Exchange(l.ctx, req.Code) if err != nil { logx.Error(err) resp.SetStatus(basic.CodeApiErr) } ses := requests.NewSession() r, err := ses.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken).Execute() if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthGoogleApiErr) } log.Println(r.Json()) googleId := r.Json().Get("id").Int() user, err := l.svcCtx.AllModels.FsUser.FindUserByGoogleId(context.TODO(), googleId) if err != nil { if err != gorm.ErrRecordNotFound { logx.Error(err) return resp.SetStatus(basic.CodeDbSqlErr) } nonce := make([]byte, 16) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOK) } l.registerInfo = &auth.RegisterToken{ Id: googleId, Password: base64.RawURLEncoding.EncodeToString(nonce), Platform: "google", OperateType: auth.OpTypeRegister, TraceId: uuid.NewString(), CreateAt: time.Now(), } l.isRegistered = false token, err := l.svcCtx.RegisterTokenManger.Encrypt(l.registerInfo) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeOAuthRegisterTokenErr) } l.registerToken = token return resp.SetStatus(basic.CodeOK) } l.isRegistered = true // 如果密码匹配,则生成 JWT Token。 jwtToken, err := auth.GenerateJwtTokenUint64(auth.StringToHash(*user.PasswordHash), l.svcCtx.Config.Auth.AccessExpire, time.Now().Unix(), user.Id, 0) // 如果生成 JWT Token 失败,则抛出错误并返回未认证的状态码。 if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeServiceErr) } l.token = jwtToken return resp.SetStatus(basic.CodeOK) } // 处理逻辑后 w,r 如:重定向, resp 必须重新处理 func (l *UserGoogleLoginLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { if resp.Code == 200 { rurl := fmt.Sprintf( l.svcCtx.Config.MainAddress+"/oauth?token=%s&is_registered=%t®ister_token=%s", l.token, l.isRegistered, l.registerToken, ) html := fmt.Sprintf(` Redirect `, rurl) fmt.Fprintln(w, html) } else { httpx.OkJson(w, resp) } }