SpringでGoogleアカウントログインを実装する


現在自社開発を進めていますが、その中でGoogleアカウントでのログイン機能を実装したのでこの話をまとめました！
初めてだったのでウキウキです。

# 1. 目標

↓のような感じでボタンを表示させて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/0cdde7ad-ecb8-63a5-4ec8-72158fc5f7a2.png)

押下するとGoogleでのログイン画面を表示させる

![googlelogin.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/be0a630e-abda-295d-6eb9-b262bda8c3c0.png)

Googleアカウントでログインして情報を受け取るところまでやっていきます！

# 2. 下準備（Google Cloud）

実装する前に一つ下準備が必要です。
Google Cloud（GCPって奴やな）でOAuth 2.0 クライアント IDを発行します。

https://cloud.google.com/?hl=ja

↓のAPIサービスから認証情報に飛びます。
![cloud.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/4b126021-86e4-1a16-c8df-9f03bb724c3d.png)

認証情報を作成からOAuthクライアントIDに行きます。
![cloud2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/1e6f9cd0-cc87-bd81-ed4a-344e8b753f1a.png)

アプリケーションの種類を問われるのでウェブアプリケーションを選択します。
承認済みのJavaScript生成元にはhttp://localhost:8080とhttp://localhostを設定します。
そして作成！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/68f54ac4-d649-b5c5-d04a-b4d84e9c6014.png)

作成完了が確認できます。
クライアントIDは後ほど使います！

![tempsnip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/0611b1f0-5428-e1ce-a1c0-4d7ae9885949.png)

あとOAuth同意画面を構成をする必要がありますが↓の記事を参考にしてください！
見やすく大変参考になりました。

https://nakanishi-s.jp/google%E3%81%A7%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%92%E5%AE%9F%E8%A3%85/

以上で下準備は完了です！

# 3. コードに落とす

こちらも参考にしたサイトがあるので共有します。
ほんとに感謝。。。！！！

https://syslog.life/2023/08/06/googleaccount-sortiallogin-java-springboot-sample/

```html:html
  <script src="https://accounts.google.com/gsi/client" async defer></script>
  <div id="g_id_onload"
    data-client_id="クライアントID"
    data-callback="afterLoginCallback"
    data-ux_mode="redirect"
    data-login_uri="押下先URL"
    data-size="small"
  >
  </div>
  <div class="g_id_signin" data-type="standard"></div>
</body>
```

上をコピペすると↓のようなボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3495456/0cdde7ad-ecb8-63a5-4ec8-72158fc5f7a2.png)

↓がGoogleログインした際に実行されるコードです。

```java:java
@PostMapping("/done")
    public ModelAndView done(final ModelAndView mav,
                             @RequestParam("clientId") final String clientId,
                             @RequestParam("credential") final String credential,
                             @RequestParam("select_by") final String selectBy,
                             @RequestParam("g_csrf_token") final String gCsrfToken
    ) throws GeneralSecurityException, IOException {
        mav.setViewName("done"); // HTMLテンプレート指定
        final GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), GsonFactory.getDefaultInstance())
        .setAudience(Collections.singletonList(clientId))
        .build();

        final GoogleIdToken idToken = verifier.verify(credential);
        if (idToken != null) {
            GoogleIdToken.Payload payload = idToken.getPayload();  
            System.out.println("selectBy:" + selectBy);
            System.out.println("gCsrfToken:" + gCsrfToken);
            System.out.println("userId:" + payload.getSubject());
            System.out.println("email:" + payload.getEmail());
            System.out.println("emailVerified:" + payload.getEmailVerified());
            System.out.println("name:" + payload.get("name"));
            System.out.println("pictureUrl:" + payload.get("picture"));
            System.out.println("locale:" + payload.get("locale"));
            System.out.println("familyName:" + payload.get("family_name"));
            System.out.println("givenName:" + payload.get("given_name"));
            
        } else {
            System.out.println("Invalid ID token.");
        } return mav;
    }
```

↓のコードが重要ですね。

```java:java
        final GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), GsonFactory.getDefaultInstance())
        .setAudience(Collections.singletonList(clientId))
        .build();
```

<details><summary>ChatGPTさんによる解説になります。長くなるので折りたたんでおきます。</summary>

```java:java
final GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), GsonFactory.getDefaultInstance())
    .setAudience(Collections.singletonList(clientId))
    .build();
```

***GoogleIdTokenVerifier*** クラスは、GoogleのIDトークンを検証するためのユーティリティクラスです。
***Builder*** クラスを使用して、新しい GoogleIdTokenVerifier インスタンスを構築しています。
NetHttpTransport() は、Google APIクライアントライブラリの一部で、HTTPトランスポートを提供します。
***GsonFactory.getDefaultInstance()*** は、Google APIクライアントライブラリの一部で、JSONデータのパースと生成のためのGsonライブラリのファクトリメソッドです。
***setAudience(Collections.singletonList(clientId))*** は、検証する対象のアプリケーションのクライアントID（clientId）を設定しています。
***build()*** は、構築された GoogleIdTokenVerifier インスタンスを取得します。
IDトークンの検証:

```java:java
final GoogleIdToken idToken = verifier.verify(credential);
```

***verifier.verify(credential)*** は、与えられた credential を使用してGoogleのIDトークンを検証します。
***credential*** はおそらくIDトークンを表す文字列やオブジェクトです。
検証に成功すると、GoogleIdToken オブジェクトが返されます。検証に失敗した場合は null が返されます。
</details>

コード上のpayloadから様々な情報を取得できます。
Googleアカウントのメールアドレスや名前、
なんならアイコンも取得できます。（***そんなことまで取得できるんかい！*** と内心突っ込みました）


# 4.終わりに
実装してみるとGoogleログイン自体は意外と簡単にできることが分かりました！
ある程度実装方法の概略をすることができたので大満足です。

Googleログイン自体にそんな時間をとられなかったのですが
実は一つ苦しんだ箇所があり。。。

それは***CORS***です。

:::note info
CORS (オリジン間リソース共有、 Cross-Origin Resource Sharing)
かっこいいね
:::

次はCORSについてまとめたいと思います。

# 5.予告
次の投稿は2024年2月16日の予定です！