在Go里面实现Google和Apple OAuth登录
本文由claude code编写,仅供参考。 在现代应用开发中,提供第三方登录已经成为标配功能。本文将详细介绍如何在Go语言中实现Google和Apple的OAuth登录,以及如何处理iOS和Android的原生登录。 一、OAuth 2.0 基础概念 OAuth 2.0是一个授权框架,允许应用在用户授权的情况下访问用户在第三方服务上的资源,而无需获取用户的密码。主要流程包括: 授权请求:引导用户到OAuth提供商的授权页面 授权确认:用户同意授权 获取授权码:重定向回应用并携带授权码 交换令牌:使用授权码换取访问令牌 访问资源:使用访问令牌获取用户信息 二、Google OAuth登录实现 2.1 前期准备 首先需要在Google Cloud Console创建项目并配置OAuth 2.0凭据: 访问 Google Cloud Console 创建新项目或选择现有项目 启用Google+ API或Google Identity服务 创建OAuth 2.0客户端ID(Web应用、iOS、Android分别创建) 配置授权重定向URI 2.2 安装依赖 go get golang.org/x/oauth2 go get golang.org/x/oauth2/google go get google.golang.org/api/oauth2/v2 2.3 Web端Google登录实现 package main import ( "context" "encoding/json" "fmt" "log" "net/http" "os" "golang.org/x/oauth2" "golang.org/x/oauth2/google" oauth2api "google.golang.org/api/oauth2/v2" "google.golang.org/api/option" ) var googleOauthConfig *oauth2.Config func init() { googleOauthConfig = &oauth2.Config{ ClientID: os.Getenv("GOOGLE_CLIENT_ID"), ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"), RedirectURL: "http://localhost:8080/auth/google/callback", Scopes: []string{ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", }, Endpoint: google.Endpoint, } } // 处理Google登录请求 func handleGoogleLogin(w http.ResponseWriter, r *http.Request) { // 生成随机state参数,防止CSRF攻击 state := generateRandomState() // 将state存储到session中 saveStateToSession(r, w, state) // 生成授权URL url := googleOauthConfig.AuthCodeURL(state, oauth2.AccessTypeOffline) http.Redirect(w, r, url, http.StatusTemporaryRedirect) } // 处理Google回调 func handleGoogleCallback(w http.ResponseWriter, r *http.Request) { // 验证state参数 state := r.FormValue("state") savedState := getStateFromSession(r) if state != savedState { http.Error(w, "Invalid state parameter", http.StatusBadRequest) return } // 获取授权码 code := r.FormValue("code") if code == "" { http.Error(w, "Code not found", http.StatusBadRequest) return } // 交换令牌 token, err := googleOauthConfig.Exchange(context.Background(), code) if err != nil { http.Error(w, "Failed to exchange token: "+err.Error(), http.StatusInternalServerError) return } // 获取用户信息 userInfo, err := getGoogleUserInfo(token) if err != nil { http.Error(w, "Failed to get user info: "+err.Error(), http.StatusInternalServerError) return } // 处理用户信息(创建或更新用户) handleUserLogin(w, r, userInfo) } // 获取Google用户信息 func getGoogleUserInfo(token *oauth2.Token) (*GoogleUserInfo, error) { ctx := context.Background() // 创建OAuth2服务 oauth2Service, err := oauth2api.NewService(ctx, option.WithTokenSource(googleOauthConfig.TokenSource(ctx, token))) if err != nil { return nil, err } // 获取用户信息 userInfo, err := oauth2Service.Userinfo.Get().Do() if err != nil { return nil, err } return &GoogleUserInfo{ ID: userInfo.Id, Email: userInfo.Email, VerifiedEmail: userInfo.VerifiedEmail, Name: userInfo.Name, GivenName: userInfo.GivenName, FamilyName: userInfo.FamilyName, Picture: userInfo.Picture, }, nil } type GoogleUserInfo struct { ID string `json:"id"` Email string `json:"email"` VerifiedEmail bool `json:"verified_email"` Name string `json:"name"` GivenName string `json:"given_name"` FamilyName string `json:"family_name"` Picture string `json:"picture"` } 2.4 Android/iOS原生Google登录处理 对于移动端原生登录,客户端会使用Google SDK获取ID Token,然后发送给后端验证: ...