先日のLINEログインに続き今回はGoogleログインのサンプルです。ファイル構成はなるべくLINEログイン同様にしたいと思いましたので、6つのファイルと “Google API Client Library for PHP” をcomposerでインストールした関係で、”composer.json”, “composer.lock”, “vendor/*” が増えています。
index.php | Googleログインのボタン設置と取得した結果の表示ページに使用 |
err.php | 特別機能させていないため不要ですが、エラー表示ページに使用 |
config.php | クライアントID、クライアントシークレットなどを定数で設定 |
init.php | 共通処理を記述(※サンプルはセッション開始のみ) |
login.php | Google側へリクエストするURL生成とリダイレクト |
callback.php | GCPのOAuth 2.0クライアント承認済みのリダイレクト URI |
composer.json, composer.lock, vendor/* | Google API Client Library for PHP 関連 |
※ Google Cloud PlatformでGoogleログイン用のクライアントを登録し、クライアントID・クライアントシークレットを取得する必要があります。
クライアントID・クライアントシークレット等を定数で定義
“config.php” に予め取得したクライアントID・クライアントシークレット等の情報を定数で定義します。
<?php
/**
* サイト情報
*/
// サイトのベースURL
define('SITE_URL_BASE', 'https://example.com/');
// LINEログインボタン設置場所などサイトホーム
define('SITE_URL_HOME', SITE_URL_BASE.'index.php');
// コールバックURL
define('SITE_URL_CALLBACK', SITE_URL_BASE.'callback.php');
// ログインURL生成とリダイレクト
define('SITE_URL_LOGIN', SITE_URL_BASE.'login.php');
// エラーページ
define('SITE_URL_ERR', SITE_URL_BASE.'err.php');
/**
* Googleクライアント設定情報
*/
// クライアントID
define('CLIENT_ID', '1234567890*****.apps.googleusercontent.com');
// クライアントシークレット
define('CLIENT_SECRET', 'GOC**********');
/**
* Googlewログイン API エンドポイント
*/
// ユーザーに認証と認可を要求する
define('GOOGLE_EP_AUTHORIZE', 'https://accounts.google.com/o/oauth2/v2/auth');
// アクセストークンを発行する
define('GOOGLE_EP_TOKEN', 'https://oauth2.googleapis.com/token');
共通処理の設定
“init.php” にGoogle側から取得した情報をセッションに保存するためセッション開始のコードを追加します。
<?php
// セッション開始
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
コールバックURLで受ける処理の設定
<?php
//
require_once 'config.php'; // 設定ファイル
require_once 'init.php'; // 共通処理
require_once 'vendor/autoload.php';
// state チェック
if( !isset($_SESSION['state']) || (int)$_SESSION['state'] !== (int)$_GET['state'] ) {
header("Location: ".SITE_URL_ERR);
exit;
}
/**
* アクセストークンを取得する
*/
// POSTするデータ
$postData = [
"grant_type" => "authorization_code",
"code" => $_GET["code"],
"redirect_uri" => SITE_URL_CALLBACK,
"client_id" => CLIENT_ID,
"client_secret" => CLIENT_SECRET
];
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_URL, GOOGLE_EP_TOKEN);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
//
$json = json_decode($response); // JSONオブジェクトをデコード
$access_token = $json->access_token; // アクセストークンを取得
$id_token = $json->id_token; // IDトークンを取得
$_SESSION['google_res_token'] = $json; // レスポンスをセッションに保存
// ## レスポンス ##
// access_token // アクセストークン。
// expires_in // アクセストークンの有効期限が切れるまでの秒数
// id_token // ユーザー情報を含むJSONウェブトークン(JWT)
// scope // ユーザーが付与する権限
// token_type // Bearer
// {
// "access_token":"eyJhb*****.YUTdG**********.AMgJc*****",
// "expires_in":2592000,
// "scope":"openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
// "token_type":"Bearer",
// "id_token":"eyJ0eXAiOi**********"
// }
/**
* IDトークンからプロフィール情報を取得する
*/
$client = new Google_Client(['client_id' => CLIENT_ID]); //
$payload = $client->verifyIdToken($id_token); //
$email = $payload['email']; // emailを取得
$userid = $payload['sub']; // ユーザー識別子
$_SESSION['google_res_verify'] = $payload; // ペイロードをセッションに保存
//
$_SESSION['login'] = true;
// var_dump($email);
// var_dump($userid);exit;
// ## レスポンス ##
// iss // IDトークンの生成URL
// azp //
// sub // ユーザー識別子
// aud // チャネルID
// email // ユーザーのメールアドレス
// email_verified //
// at_hash //
// nonce //
// name // ユーザーの表示名
// picture // ユーザープロフィールの画像URL
// given_name // 名
// family_name // 性
// locale //
// iat // IDトークンの生成時間(UNIXタイム)
// exp // IDトークンの有効期限(UNIXタイム)
// {
// "iss":"https://accounts.google.com"",
// "azp":"**********.apps.googleusercontent.com",
// "aud":"**********.apps.googleusercontent.com",
// "sub":"12345.....",
// "email":"user@example.com"
// "email_verified":"true"
// "at_hash":"",
// "nonce":"",
// "name":"Takuo Fukao",
// "picture":"https://lh3.googleusercontent.com/a/0hdEi.....",
// "given_name":,
// "family_name":,
// "locale":"ja",
// "iat":1655439507,
// "exp":1655443107,
// }
// セッションデータを書き込みセッションを終了する
session_write_close();
//
header("Location: ".SITE_URL_HOME);
exit;
Google側へリクエストするURL生成処理の設定
“login.php” にGoogleログインを行う際、Google側へリクエストするURLの生成とリダイレクト処理を設置します。
<?php
//
require_once 'config.php'; // 設定ファイル
require_once 'init.php'; // 共通処理
//
$state = rand();
$_SESSION['state'] = $state;
$nonce = hash('sha512', openssl_random_pseudo_bytes(128));
//
$url = GOOGLE_EP_AUTHORIZE.'?' . http_build_query([
'response_type' => 'code',
'client_id' => CLIENT_ID,
'redirect_uri' => SITE_URL_CALLBACK,
'state' => $state,
'nonce' => $nonce,
'scope' => 'openid email profile',
]);
//
header("Location: ".$url);
exit;
Googleログインのボタン設置と結果の表示
“index.php” にGoogleログインのボタンの設置とGoogleログイン処理で、”callback.php” で受け取った情報を表示します。
<?php
//
require_once 'config.php'; // 設定ファイル
require_once 'init.php'; // 共通処理
// セッションから情報取得
$google_res_token = $_SESSION['google_res_token'] ? $_SESSION['google_res_token'] : '';
$google_res_verify = $_SESSION['google_res_verify'] ? $_SESSION['google_res_verify'] : '';
?><!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Googleログイン</title>
</head>
<body>
<h1>Googleログイン</h1>
<div>
<p>
<a href="<?php echo SITE_URL_LOGIN; ?>">Googleでログインする</a>
</p>
</div>
<?php if ( $google_res_token ): ?>
<div>
<h2>アクセストークンを取得する</h2>
<table>
<tr>
<th>access_token</th>
<td><?php echo $google_res_token->access_token;?></td>
</tr>
<tr>
<th>expires_in</th>
<td><?php echo $google_res_token->expires_in;?></td>
</tr>
<tr>
<th>id_token</th>
<td><?php echo $google_res_token->id_token;?></td>
</tr>
<tr>
<th>scope</th>
<td><?php echo $google_res_token->scope;?></td>
</tr>
<tr>
<th>token_type</th>
<td><?php echo $google_res_token->token_type;?></td>
</tr>
</table>
</div>
<?php endif; ?>
<?php if ( $google_res_verify ): ?>
<div>
<h2>IDトークンからプロフィール情報を取得する</h2>
<table>
<tr>
<th>iss</th>
<td><?php echo $google_res_verify["iss"];?></td>
</tr>
<tr>
<th>azp</th>
<td><?php echo $google_res_verify["azp"];?></td>
</tr>
<tr>
<th>sub</th>
<td><?php echo $google_res_verify["sub"];?></td>
</tr>
<tr>
<th>aud</th>
<td><?php echo $google_res_verify["aud"];?></td>
</tr>
<tr>
<th>email</th>
<td><?php echo $google_res_verify["email"];?></td>
</tr>
<tr>
<th>email_verified</th>
<td><?php echo $google_res_verify["email_verified"];?></td>
</tr>
<tr>
<th>at_hash</th>
<td><?php echo $google_res_verify["at_hash"];?></td>
</tr>
<tr>
<th>nonce</th>
<td><?php echo $google_res_verify["nonce"];?></td>
</tr>
<tr>
<th>name</th>
<td><?php echo $google_res_verify["name"];?></td>
</tr>
<tr>
<th>picture</th>
<td><?php echo $google_res_verify["picture"];?></td>
</tr>
<tr>
<th>given_name</th>
<td><?php echo $google_res_verify["given_name"];?></td>
</tr>
<tr>
<th>family_name</th>
<td><?php echo $google_res_verify["family_name"];?></td>
</tr>
<tr>
<th>locale</th>
<td><?php echo $google_res_verify["locale"];?></td>
</tr>
<tr>
<th>iat</th>
<td><?php echo $google_res_verify["iat"];?></td>
</tr>
<tr>
<th>exp</th>
<td><?php echo $google_res_verify["exp"];?></td>
</tr>
</table>
</div>
<?php endif; ?>
</body>
</html>
動作環境情報
"エックスサーバー" スタンダード(旧X10) "PHP" 7.4.28 "MariaDB" 10.5
Google公式ドキュメント
バックエンドサーバーで認証する | Google Sign-In for Websites | Google Developers
Authenticate with a backend server | Authentication | Google for Developers
コメント