GolangでGoogle OAuthでのアカウント連携をする
目的
Googleアカウントとの連携させるためにGoogle OAuthを用いてGoogleアカウントIDを取得する。
今回はGCPでのアプリの設定などは省いています。
大まかな処理の流れの整理
1: ユーザーが連携するリクエストをサービスのAPIに投げかける
↓
2: stateトークンをAPIが発行し、Googleアカウントでのログイン画面のURLにstateトークンとscope、ClientIDを繋げてフロントに返す
↓
3: 返ってきたログインURLにリダイレクトし、同意を求める画面が表示されるので確認したらGoogleの認証サーバーからAuthorization code(以下codeと表示します)が発行されます。
↓
4: stateトークンとGoogleから返されたcodeをAPI側へ送り、以前自身が発行したstateトークンかどうかをAPI側が判断します。
↓
5: 確認できれば、API側からGoogleへアクセスしてcodeをGoogle側が相違ないと判断しユーザー情報を返します。
↓
6: API側が取得したGoogleアカウント情報の一部をDBに保存し、ログイン時にサービスのUserIDと紐付けて連携が完了する。
そして、Googleアカウントでもログインできるようになる。
GoogleアカウントIDを取得する部分のコード
package infrastructure
import (
"context"
"errors"
"golang.org/x/oauth2"
googleOAuth "golang.org/x/oauth2/google"
v2 "google.golang.org/api/oauth2/v2"
)
type Google struct {
Config *oauth2.Config
}
func NewGoogle(c *Config) *Google {
return newGoogle(c)
}
func newGoogle(c *Config) *Google {
google := &Google{
Config: &oauth2.Config{
ClientID: c.Google.ClientID,
ClientSecret: c.Google.ClientSecret,
Endpoint: googleOAuth.Endpoint,
Scopes: []string{"openid"},
RedirectURL: "http://localhost:8080/auth/callback/google",
},
}
if google.Config == nil {
panic("==== invalid key. google api ====")
}
return google
}
func (g *Google) GetLoginURL(state string) (clientID string) {
return g.Config.AuthCodeURL(state)
}
func (g *Google) GetUserID(code string) (googleUserID string, err error) {
cxt := context.Background()
httpClient, _ := g.Config.Exchange(cxt, code)
if httpClient == nil {
return "", errors.New("接続エラー")
}
client := g.Config.Client(cxt, httpClient)
service, err := v2.New(client)
if err != nil {
return "", errors.New("接続エラー")
}
userInfo, err := service.Tokeninfo().AccessToken(httpClient.AccessToken).Context(cxt).Do()
if err != nil {
return "", errors.New("接続エラー")
}
return userInfo.UserId, nil
}
基本的に記述はドキュメントを参考にしています。
userInfo, err := service.Tokeninfo().AccessToken(httpClient.AccessToken).Context(cxt).Do()
この箇所で取得したものには下記の構造体が返されてくる(パッケージ内から抜粋)
type Tokeninfo struct {
Audience string `json:"audience,omitempty"`
Email string `json:"email,omitempty"`
ExpiresIn int64 `json:"expires_in,omitempty"`
IssuedTo string `json:"issued_to,omitempty"`
Scope string `json:"scope,omitempty"`
UserId string `json:"user_id,omitempty"`
VerifiedEmail bool `json:"verified_email,omitempty"`
googleapi.ServerResponse `json:"-"`
ForceSendFields []string `json:"-"`
NullFields []string `json:"-"`
}
今回はこの中からUserIdを取得しサービスのUserIDを紐付けている。
まとめ
・stateトークンーAPI側が発行し、操作したユーザーで相違ないとして不正なアクセスでないことをAPI側が判断する
・Authorization codeー認証サーバー(今回だとGoogle側)から発行され、これもGoogleが当サービスの正当性を確認するために発行されるもの
今回はGoogleアカウントとサービスのUserIDを紐付けることを目的としているのでGoogleアカウントのUserIdではなくアクセストークンのがいいのではないかなどありますが、認可や認証などまとめて書いていこうと思います。
Author And Source
この問題について(GolangでGoogle OAuthでのアカウント連携をする), 我々は、より多くの情報をここで見つけました https://zenn.dev/sgtkuc1118/articles/693e2930f8151c著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol