Google OAuthを使用したAndroidでのセキュアなログインの作成

PubNub Developer Relations - Mar 11 - - Dev Community

2022年1月現在、45億5,000万人が少なくとも1つのソーシャル・メディア・プロフィールを持っていると推定されており、大半のアプリケーションが、ユーザーが簡単に参加できる方法として、ある種のソーシャル・サインインを持っていることは驚くことではない。これは、ユーザー・エクスペリエンスを向上させる鍵となる。開発の観点から見ると、フェイスブック、ツイッター、グーグルのようなソーシャルサインイン・プロバイダーには大きな共通点がある。その共通のパズルのピースがOAuthであり、より具体的にはOAuth 2.0である。しかし、単にOAuthを使用するだけではなく、スコープ、OAuthクライアントID、OAuth同意画面について正しく理解し、最適な実装を行う必要があります。

認証(Authentication)と認可(Authorization)の違いは何ですか?

認証(authn)とは、ユーザーを識別または検証するプロセスを指し、この文脈ではGoogle OAuthを介して行うことができます。一方、認可(authz) は、認証されたユーザが特定のリソースにアクセスするために必要な権限を持っているかどうかに関係します。OAuthのパーミッションを定義するスコープが重要な役割を果たします。

authnとauthzの両方は密接に関連しており、通常OAuth 2.0のプロセスの中で見られます。どちらのプロセスでも、クライアント ID とクライアントシークレットを保持するサーバーが必要になりますが、これは Google Cloud を使って管理できます。

Authn と Authz の OAuth への適合性

OAuthは厳密には認可のための標準ですが、開発者の間で大きな誤解があるのは、Authn(認証)がその一部であるということです。OAuth 2.0は、特にGoogleのようなソーシャル・プラットフォームでは、ネイティブ・テクノロジー、Javascript、Kotlinを組み合わせて処理を連続して実行するauthnも取り入れている。

ここにプロセスの概要を示す:

見ての通り、2つの主要なコンポーネントがある。最初に、ユーザーから必要な承認を得る必要がある。これはユーザーがサインインしている場合に行われ、多くのAPIはここでopenidを使用してOAuthの認証部分と結びつける。ユーザーアカウントの権限から許可を得たら、リソースの所有者と通信を開始することができます。認可サーバーにグラントを送信すると、アクセストークンが返ってきます。このアクセストークンを使って、ユーザーに関連する必要な情報にアクセスすることができます。

OAuth2.0を実装する際には、正しいリダイレクトURIとコールバックを設定することが重要です。これらのパラメータに少しでもミスがあると、authnとauthzのプロセスが失敗する可能性があるからです。さらに、セキュリティとユーザー体験を向上させる一環として、GoogleはOAuth 2.0用のクローム拡張機能を提供しています。

AndroidでのGoogleサインインによる認証

Androidのアプリケーション、特にGoogleサインインによる認証は、一般的なセキュリティ対策です。しかし、単にAndroidアプリケーションにGoogleを追加するだけではなく、OAuthを理解し、SDKとGoogle APIを掘り下げることから始まります。

Google Sign-inを始めるにあたり、サーバーとなるPubNubの機能であるFunctionsを使用する。これらの関数を使うことで、OAuthプロセスにおける通知の実装がよりシンプルになる。OAuthプロセスのコードスニペットもGitHubにあります。

また、Google APIアカウントを正しいパッケージ名で設定し、OAuthクライアントIDとOAuth同意画面を設定していることを確認してください。

次に、Android アプリケーションに Google を追加してサインイン処理を開始できるようにします。まず、プロジェクトレベルのGradleファイルにrepositories { google() }という行があることを確認してください。これでアプリケーションがGoogle SDKを利用できるようになります。

次に、アプリレベルの Gradle ファイルに移動し、Google Play services auth 依存関係を更新します。2022年1月現在、最新バージョンはcom.google.android.gms:play-services-auth:19.2.0です。

    implementation 'com.google.android.gms:play-services-auth:19.2.0'
Enter fullscreen mode Exit fullscreen mode

さて、更新された依存関係がプロジェクトに追加されましたが、サインインプロセスはまだ実行できません。Androidマニフェストファイルを編集して、Firebaseに関するインターネットパーミッションを追加する必要があります:

    <uses-permission android:name="android.permission.INTERNET" />
Enter fullscreen mode Exit fullscreen mode

Google サインインボタンの追加

この段階はかなり簡単です。サインインコンポーネントをactivity_main.xmlファイルに追加します。サインインボタンはGoogleによってスタイリングされますが、念のためGoogleのブランドガイダンスを確認してください。デスクトップアプリでは優れたユーザーエクスペリエンスが重要であり、これにはサインインボタンで使用されるスタイリングや識別子が含まれることを忘れないでください。

    <com.google.android.gms.common.SignInButton
                android:id="@+id/sign_in_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="8dp"
                app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp"
                app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
                app:layout_constraintVertical_bias="0.665"
    />
Enter fullscreen mode Exit fullscreen mode

Androidアプリでは、Googleサインインによる認証は一般的なセキュリティ対策です。ここでは、このプロセスがMainActivityでどのように動作するかの例を示します。このスニペットは、Kotlinを使ってGoogleサインインを実装するためのガイドとなります。

class MainActivity : AppCompatActivity() {
    private val RC_SIGN_IN = 9001
    private var mGoogleSignInClient: GoogleSignInClient? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.server_client_id))
            .requestEmail()
            .build()
        mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
    }
    public override fun onStart() {
        super.onStart()
        val mGmailSignIn = findViewById<SignInButton>(R.id.sign_in_button)
        val account = GoogleSignIn.getLastSignedInAccount(this)
        Log.w("Sign In: ", account.toString())
        mGmailSignIn.setOnClickListener {
                signIn()
        }
    }
    public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == RC_SIGN_IN) {
            val task = GoogleSignIn.getSignedInAccountFromIntent(data)
            handleSignInResult(task)
        }
    }
    private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
        Log.w("Sign In: ", completedTask.toString())
        try {
            val account = completedTask.getResult(ApiException::class.java)
            val idToken = account!!.idToken
            Log.w("Sign In: ", idToken.toString())
            authCheck(idToken.toString())
        } catch (e: ApiException) {
            Log.w("Sign In: ", "signInResult:failed code=" + e.statusCode)
        }
    }
    private fun signIn() {
        val signInIntent = mGoogleSignInClient!!.signInIntent
        startActivityForResult(signInIntent, RC_SIGN_IN)
    }
    private fun authCheck(token: String) {
        // Instantiate the RequestQueue.
        val queue = newRequestQueue(this)
        val url = "https://pubsub.pubnub.com/v1/blocks/sub-key/sub-c-87dbd99c-e470-11e8-8d80-3ee0fe19ec50/google?token=$token"
        // Request a string response from the provided URL.
        val stringRequest = StringRequest(
            Request.Method.GET, url,
            Response.Listener<String> { response ->
                // Display the first 500 characters of the response string.
                Log.d("Response: ", response)
            },
            Response.ErrorListener {Log.d("Response: ", "Didn't Work!")})
        // Add the request to the RequestQueue.
        queue.add(stringRequest)
    }
}
Enter fullscreen mode Exit fullscreen mode

上記のコードで、あなたのアプリはユーザーを認証・検証できるようになりました!認証に成功したら、次はアクセストークンを取得します。このプロセスは前のものとよく似ていますが、今回はトークンの URL -https://www.googleapis.com/oauth2/v4/tokenHTTP POSTリクエストを送信します。これはJavaScriptを使って行うことができ、コードはGitHubにありますので参考にしてください。

あなたのPubNubファンクションは以下のようになるでしょう:

export default (request, response) => {
    const pubnub = require('pubnub');
    const xhr = require('xhr');
    let headersObject = request.headers;
    let paramsObject = request.params;
    let methodString = request.method;
    let bodyString = request.body;
    // Set the status code - by default it would return 200
    response.status = 200;
    // Set the headers the way you like

    var client_id = "your google client id"
    var client_secret = "your google client secret";
    var redirect = "https://pubsub.pubnub.com/v1/blocks/sub-key/sub-c-87dbd99c-e470-11e8-8d80-3ee0fe19ec50/Auth";

    response.headers['X-Custom-Header'] = 'CustomHeaderValue';
    var dataString = `client_id=${client_id}&client_secret=${client_secret}&redirect_uri=${redirect}&grant_type=authorization_code&code=CODE`;
    var url = `https://www.googleapis.com/oauth2/v4/token${dataString}`;
    var options = {
        "method": 'POST',
        "body": dataString,
    };

    console.log(dataString);
    return xhr.fetch(url, options).then((x) => {
        const body = JSON.parse(x.body);
        console.log(body);
         return response.send(body);
    }).catch((err) => {
        // console.log(err)
        return response.send("Malformed JSON body.");
    });
};
Enter fullscreen mode Exit fullscreen mode

このコードを MainActivity.ktファイルに追加することで実現できます:

Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
    GoogleSignInAccount account = task.getResult(ApiException.class);
    String authCode = account.getServerAuthCode();
    // Show signed-un UI
    updateUI(account);
    // TODO(developer): send code to server and exchange for access/refresh/ID tokens
} catch (ApiException e) {
    Log.w(TAG, "Sign-in failed", e);
    updateUI(null);
}
Enter fullscreen mode Exit fullscreen mode

これで、あなたのAndroidアプリにOAuth 2.0を使ったGoogleサインインを実装し、ユーザーエクスペリエンスをスムーズにし、アプリを安全に保つことができます。

オープンなインターネットでアプリケーションをテストした後、問題なくサインアッププロセス全体をナビゲートできるはずです。このプロセスには、アプリに設定できる様々なスコープ(権限)が付属している認証用のGoogle OAuthが関係するかもしれません。ユーザーエクスペリエンスはシームレスであるべきだということを忘れないでください。

さて、ここまででOAuthクライアントIDベースの認証と認可の違いについて理解が深まったと思います。この知識をもとに、OAuthの同意画面を通してユーザーがサインインした後に何ができるかを調べ始めましょう。

クライアント側 SDK のパッケージ名は、JavaScript、Kotlin、または別のプラットフォームのネイティブであっても、Google Cloud プロジェクトに登録されているものと一致する必要があります。このページでアクセスできない外部コンテンツがある場合は、https://pubsub-quickstart-app.pubnub.com/signup から表示することもできます。このページでは、OAuthに必要なリダイレクトURIとコールバックパラメータの正しい使い方を示す必要があります。

PubNubの支援が必要ですか?

PubNubのプラットフォームは、Webアプリ、モバイルアプリ、デスクトップアプリ、IoTデバイス向けにリアルタイムのインタラクティブ機能を構築、配信、管理するためのリソースを開発者に提供します。高度なインタラクションのために、通知でユーザーを巻き込んだり、ユニークな識別子を持つプライベートFirebaseアプリケーションを作成することができます。

当社のプラットフォームのバックボーンは、業界最大かつ最もスケーラブルなリアルタイムエッジメッセージングネットワークです。Google Cloudサービスを採用し、Chromeと統合することでさらに機能を強化し、世界中に15以上の拠点を持ち、8億人の月間アクティブユーザーをサポートし、99.999%の信頼性を誇るため、トラフィックの急増による停止、同時実行数の制限、遅延の問題を心配する必要はありません。

PubNubの始め方

ライブツアーをチェックして、5分以内にすべてのPubNub搭載アプリの背後にあるコアコンセプトに慣れてください。OpenIDはこれらのコンセプトの重要な一部となります。PubNubアカウントにサインアップすると、PubNubキーに無料ですぐにアクセスできます。PubNubのドキュメントは、ユースケースや好みのSDKに関係なく、詳細なパラメータを持つコードスニペットまたは "スニペット "を含む、インストールとセットアップのプロセスを案内します。

目次

認証と認可の違いは何ですか?AuthnとAuthzがOAuthにどのように適合するかAndroidでGoogleサインインで認証するGoogleサインインボタンを追加するPubNubの支援が必要ですか?PubNubを始めるには

PubNubはあなたのお役に立ちますか?

この記事はPubNub.comに掲載されたものです。

私たちのプラットフォームは、開発者がWebアプリケーション、モバイルアプリケーション、およびIoTデバイスのためのリアルタイムのインタラクティブ機能を構築、配信、管理するのに役立ちます。

私たちのプラットフォームの基盤は、業界最大かつ最もスケーラブルなリアルタイムエッジメッセージングネットワークです。世界15か所以上で8億人の月間アクティブユーザーをサポートし、99.999%の信頼性を誇るため、停電や同時実行数の制限、トラフィックの急増による遅延の問題を心配する必要はありません。

PubNubを体験

ライブツアーをチェックして、5分以内にすべてのPubNub搭載アプリの背後にある本質的な概念を理解する

セットアップ

PubNubアカウントにサインアップすると、PubNubキーに無料ですぐにアクセスできます。

始める

PubNubのドキュメントは、ユースケースやSDKに関係なく、あなたを立ち上げ、実行することができます。

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .