はじめに
Web開発を行うにあたってログイン機能の追加は多くの人が通る道だと思います。そんなログイン機能の中で最も使われているであろうGoogleのGmailを使用したログイン機能の実装をGo言語で行う方法をまとめた記事です。
実装手順
プロジェクトの作成
まず、Google Cloud Consoleで新しいプロジェクトを作成します。以下の手順に従ってください
プロジェクト作成画面への遷移
- Google Cloud Consoleにアクセスします
- 画面上部の「プロジェクトの作成」ボタンをクリックします
プロジェクト詳細の設定
プロジェクト作成完了
プロジェクトの作成が完了すると、以下の画面に遷移します。この画面で、新しく作成したプロジェクトが選択された状態になっていることを確認してください。
OAuth2.0 クライアントの作成
Gmailログイン機能の実装には、OAuth 2.0認証プロトコルを使用します。以下の手順で認証情報を設定します。
認証情報の作成
クライアント情報の設定
- アプリケーションの種類で「ウェブアプリケーション」を選択します
- クライアント名を入力します
- 承認済みのJavaScript生成元に
http://localhost:8080
を入力します - 承認済みのリダイレクトURIに
http://localhost:8080/auth/google/callback
を入力します
これらが入力できるとページ下の作成ボタンをクリックして作成してください。
認証情報の取得
作成が完了すると、クライアントID
とクライアントシークレット
が表示されます。これらは環境変数として後の実装で使用するため、安全に保管してください。
コード実装
実装前の準備
mkdir demo
cd demo
mkdir main.go
mkdir templates
touch templates/index.html
touch .env
code .
main.goの実装
package main
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/joho/godotenv"
"github.com/markbates/goth"
"github.com/markbates/goth/gothic"
"github.com/markbates/goth/providers/google"
)
func main() {
// Ginルーターの初期化
r := gin.Default()
// .envファイルの読み込み(環境変数の設定)
err := godotenv.Load()
if err != nil {
log.Fatal(".envファイルの読み込みに失敗しました!")
}
// 環境変数からOAuth認証に必要な情報を取得
clientID := os.Getenv("CLIENT_ID")
clientSecret := os.Getenv("CLIENT_SECRET")
clientCallbackURL := os.Getenv("CLIENT_CALLBACK_URL")
// 必要な環境変数が設定されているか確認
if clientID == "" || clientSecret == "" || clientCallbackURL == "" {
log.Fatal("環境変数(CLIENT_ID、CLIENT_SECRET、CLIENT_CALLBACK_URL)が必要です")
}
// Googleプロバイダを使用したOAuth認証の設定
// スコープを明示的に指定:ユーザー情報とメールアクセス
googleProvider := google.New(
clientID,
clientSecret,
clientCallbackURL,
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
)
goth.UseProviders(googleProvider)
// HTMLテンプレートの読み込み
r.LoadHTMLGlob("templates/*")
// ルーティングの設定
r.GET("/", home) // トップページ
r.GET("/auth/:provider", signInWithProvider) // 認証開始エンドポイント
r.GET("/auth/:provider/callback", callbackHandler) // コールバックエンドポイント
r.GET("/success", Success) // 認証成功後のページ
// サーバーの起動(8080ポート)
r.Run(":8080")
}
func home(c *gin.Context) {
// インデックスページのテンプレート読み込み
tmpl, err := template.ParseFiles("templates/index.html")
if err != nil {
// テンプレート読み込みエラー時は500内部サーバーエラーを返す
c.AbortWithStatus(http.StatusInternalServerError)
return
}
// テンプレートの実行
err = tmpl.Execute(c.Writer, gin.H{})
if err != nil {
// テンプレート実行エラー時は500内部サーバーエラーを返す
c.AbortWithStatus(http.StatusInternalServerError)
return
}
}
func signInWithProvider(c *gin.Context) {
// 認証プロバイダの取得(この場合はGoogle)
provider := c.Param("provider")
q := c.Request.URL.Query()
q.Add("provider", provider)
c.Request.URL.RawQuery = q.Encode()
// 認証プロセスの開始
gothic.BeginAuthHandler(c.Writer, c.Request)
}
func callbackHandler(c *gin.Context) {
// 認証プロバイダの取得
provider := c.Param("provider")
q := c.Request.URL.Query()
q.Add("provider", provider)
c.Request.URL.RawQuery = q.Encode()
// ユーザー認証の完了
user, err := gothic.CompleteUserAuth(c.Writer, c.Request)
if err != nil {
// 認証エラー時は500内部サーバーエラーを返す
c.AbortWithError(http.StatusInternalServerError, err)
return
}
// ユーザー情報をログに出力
log.Printf("ログインユーザー情報:")
log.Printf("プロバイダ: %s", user.Provider)
log.Printf("ユーザーID: %s", user.UserID)
log.Printf("ニックネーム: %s", user.NickName)
log.Printf("メールアドレス: %s", user.Email)
log.Printf("名前: %s", user.Name)
log.Printf("画像URL: %s", user.AvatarURL)
// 認証成功後、successページにリダイレクト
c.Redirect(http.StatusTemporaryRedirect, "/success")
}
func Success(c *gin.Context) {
// 認証成功後に表示するシンプルなHTMLページ
c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(fmt.Sprintf(`
<div style="
background-color: #fff;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center;
">
<h1 style="
color: #333;
margin-bottom: 20px;
">ログインに成功しました!</h1>
</div>
</div>
`)))
}
今回の実装ではgoth
とgothic
ライブラリを使用して、Googleのログイン機能を簡単に実装しています。
主に3つの重要な関数で構成されています:
1. ログイン開始 (signInWithProvider
)
ユーザーがGoogleログインボタンをクリックすると、Googleの認証ページにリダイレクトされます
gothic.BeginAuthHandler()
が認証プロセスを開始させる関数です
2. コールバック処理 (callbackHandler
)
Googleからユーザー情報を受け取る
ログイン成功後のユーザー情報を取得
ユーザーのメールアドレス、名前、プロフィール画像などにアクセス可能
ここでセッションの追加やDBへの保存の関数の呼び出しを行う
3. 成功ページ (Success
)
ログイン成功後に表示されるシンプルな画面
スコープの設定
googleProvider := google.New(
clientID,
clientSecret,
clientCallbackURL,
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
)
userinfo.email: ユーザーのメールアドレスにアクセス
userinfo.profile: ユーザーの基本プロファイル情報にアクセス
他の一般的なGoogleスコープ例
- https://www.googleapis.com/auth/drive: Googleドライブへのアクセス
- https://www.googleapis.com/auth/calendar: カレンダーへのアクセス
- https://www.googleapis.com/auth/contacts: 連絡先へのアクセス
以下に、他のスコープに関するリファレンスがありますので以下から必要なスコープを探して追加してください。
https://developers.google.com/identity/protocols/oauth2/scopes?hl=ja
ログイン前のホーム画面の作成
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign in with Google</title>
</head>
<body
style="
font-family: Arial, sans-serif;
background-color: #f0f0f0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;"
>
<div
style="
background-color: #fff;
padding: 40px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center;"
>
<h1 style="color: #333; margin-bottom: 20px;">Welcome</h1>
<a href="/auth/google" style="
display: inline-flex;
align-items: center;
justify-content: center;
background-color: #4285f4;
color: #fff;
text-decoration: none;
padding: 12px 20px;
border-radius: 4px;
transition: background-color 0.3s ease;">
<span style="font-size: 16px; font-weight: bold;">Sign in with Google</span>
</a>
</div>
</body>
</html>
環境変数の設定
CLIENT_ID=clientID
CLIENT_SECRET=clientSecret
CLIENT_CALLBACK_URL=http://localhost:8080/auth/google/callback
環境変数として、以下のものを定義しています
-
CLIENT_ID
: Googleから取得したクライアントID -
CLIENT_SECRET
: クライアントシークレット -
CLIENT_CALLBACK_URL
: 認証後のリダイレクトURL
プロジェクトの依存関係 初期化
go mod init demo
go mod tidy
実装確認
以下のコマンドで実装したコードを試してみましょう
go run main.go
エラーなく実行できていたら以下のURLにアクセスしてみてください
http://localhost:8080/
アクセスするとこのようにログインのためのボタンだけのページが表示されます。
ログインが成功すると以下のような画面になります。
また、実行しているGoのターミナルで実際にログインしたユーザーの情報を確認できます。
参考