PythonでGoogle Sign-Inを使用して認証の実装
はじめに
サービスを作るときに、一部のユーザーのみ提供したい場合があるでしょう。
社内で、ビジネスを加速させるために、データサイエンスツールを作っていた。社内限定なツールなので、アクセス制限が必要です
弊社は全員Gmail使用するため、ユーザーシステムを持たずに、Google Sign-In経由、手軽に認証システムを作りました。
本文は、Google Sign-Inを使用するユーザー認証のプロセスを紹介します。構成は以下です:
「Talk is cheap, show me the code.」を信じている人は、「Google Sign-Inを用いた認証のプロセス」の部分だけ見れば良い。
自分の理解が限られるなので、もし不適切なところがありましたら、ご指摘いただけると幸いです。
OAuthとGoogleログインの紹介
OAuthが広く使われている概念ですが、自体はややこしいなので、誤解されていることがあるでしょう。先に関連する概念を説明します。
基本概念
認証(Authentication、AuthN):通信の相手が誰(何)であるかを確認すること。
認可(Authorization、AuthZ):とある特定の条件に対して、リソースアクセスの権限を与えること。
なので、認可には、「誰」という概念はなく、「リソース」という概念が必要。リソースに対してアクセス可否を判断することです。 リソースの定義は略、WebページやAPIやなどのことです。
OAuth:権限の認可を行うためのプロトコルである。現時点の標準は2.0版なので、OAuth2と呼ばれている。
OpenID Connect:OAuth 2.0 プロトコルの上にシンプルなアイデンティティレイヤーを付与したものである。
簡単に言うと
OpenID Connect = OAuth2 + Identity Layer
Google Sign-In:Googleアカウントでサインイン、軽減する認証システムです。Googleユーザーと連結することもできます。
Google Sign-Inは、OAuth 2.0のプロトコルに従っています。
出典:https://developers.google.com/identity?hl=ja
OAuth2認可のプロセス
OAuth2に関する4つのロール
Resource Owner:リソースへのアクセス権限を与えられる人またはエンティティ。例えば、ユーザー。
Resource Server:リソースを格納するかつAccessTokenを使ったリソースリクエストに応えられるサーバー。例えば、Facebook・Google・GithubのAPIサーバー。
Client:Resource Ownerの代理として、リソースを要求するアプリケーション。例えば、Kaggle(Facebookでログインできます)。
Authorization Server:例えば、Facebook・Google・Githubの認証サーバー。
OAuth2認可プロセス
OAuth2における、認可の流れは以下です:
+--------+ +---------------+ | |--(A)- Authorization Request ->| Resource | | | | Owner | | |<-(B)-- Authorization Grant ---| | | | +---------------+ | | | | +---------------+ | |--(C)-- Authorization Grant -->| Authorization | | Client | | Server | | |<-(D)----- Access Token -------| | | | +---------------+ | | | | +---------------+ | |--(E)----- Access Token ------>| Resource | | | | Server | | |<-(F)--- Protected Resource ---| | +--------+ +---------------+
出典:https://tools.ietf.org/html/rfc6749
簡単に説明すると、
- ClientはResouce Ownerに特定リソースの権限を要求する、Resouce Ownerは権限付与を同意(Authorization Grantを発行)する
- ClientはAuthorization GrantをAuthorization Serverに見せて、AccessTokenを要求する。Authorization Serverは検証し、AccessTokenをClientに渡します。
- ClientはAccessTokenを使って、Resource Serverにリソースを要求する、Resource ServerはAccessTokenを検証し、リクエストの結果を返す。
具体出来に、どう検証するのか、GoogleにおけるOAuth2の認可のプロセスの部分に参照してください。
承認のフローがややこしいなので、詳細は
に参考してください。
Open Id Connect のプロセス
Open Id Connectの流れは以下です、説明が略。
+--------+ +--------+ | | | | | |---------(1) AuthN Request-------->| | | | | | | | +--------+ | | | | | | | | | | | End- |<--(2) AuthN & AuthZ-->| | | | | User | | | | RP | | | | OP | | | +--------+ | | | | | | | |<--------(3) AuthN Response--------| | | | | | | |---------(4) UserInfo Request----->| | | | | | | |<--------(5) UserInfo Response-----| | | | | | +--------+ +--------+
出典: https://openid.net/specs/openid-connect-core-1_0.html
なぜOAuth2が必要なのか
下記の仮想ユースケースから説明します。
ユーザーAは、Googleアカウントを持っています。そして、幾つのリソースが持っています:
- メールアドレス
- アイコン
- 年齢情報
- など
ユーザーが自分のユーザー名とパースワードでログインするから、リソースの訪問することができます。
ユーザーAは、あるアプリBで、活動するために、Googleアカウントの特定情報(例えばアイコン)が必要です。
アプリBが、ユーザーAのGoogleアカウントの特定のリソースをアクセスすることが必要となっています。
しかし、このリソースはプラベートなので、A以外は誰でも訪問出来ない。Aは、リソース訪問権限をBに付与したい場合は、どうすればいいでしょうか?
方法1:ユーザーAはアカウントとパスワードをBに渡し、Bはリソースをアクセスする。
リソースのアクセスができますが、以下のデメリットがあります:
- 安全ではありません:パースワードを渡すのは怖いでしょう
- 権限が大きい:Bが認証を取得すると、Aのすべてのリソースにアクセスできる
- 簡単にキャンセルできない:パースワードを変更する以外は認証を失効されることはできない
方法2:ユーザーAが一定期間内、特定リソースへアクセスする「トークン」をBに渡す、Bはこの「トークン」を持って、リソースを訪問します。
パスワードより、トークンは以下のメリットがあります:
- パスワードが漏らない
- 特定のサービスに限定できる
- 期間を過ぎたら失効出来る
Access Tokenの理解
お客さん、会社に見学することをイメージして。
お客さんの資格を審査し、お客さんシールと食券を渡します。社員のセキュリティカードと違うものです。
お客さんはシールを使って、会社の特定なエリアで見学できますし、食券を使って食事もできます、でもそれ以外のコンフィデンシャルのところの立ち入ることはできない。
見学終了あと、シールと食券の使用はできなくなて、再入場の場合、再度の審査とシールの再発行が必要です。
トークンは似てるなものです。
Google Sign-Inを用いた認証のプロセス
「Google Sign-In」での認証実際は、GoogleのOAuth2サービスを使って、ユーザーからGoogleアカウント情報をアクセスの認可をもらえて、ユーザーのGoogleアカウントの情報を使って、ユーザーをウェブサイトの訪問を許すかどうか判断することです。
GoogleにおけるOAuth2の認可のプロセス
OAuth2認証のプロセスに従って、GoogleSignInのプロセスを説明します。
権限を要求する
ユーザーがログインボタンを押すとき、ClientはGoogle Login画面をリダイレクトして、権限を要求する。ユーザーを同意すると、権限を付与されます。
権限付与のとき、(事前発行した)client_idや、同意するscopeをGoogleに渡します。
AccessTokenを要求する
ユーザーが同意する後、GoogleはClientを事前登録したCallbackのUriを叩いて、(Grant)codeを渡します。 Clientはそのcodeとclient_id, client_secretを使って、AuthAPIを叩き、AccessTokenを請求します。 Google側が検証して、AccessTokenをResponseで返します。
リソースを請求する
一定期間内、返したAccessTokenを使って、ユーザーのリソースをアクセス出来ます。
PythonでGoogle Sign-Inで認証の実装
事前準備
ウェブアプリはGoogleAuthを登録して、以下の情報をもらえます:
- client_id
- client_secret
そして、以下の情報を、Googleに登録します:
- domain
- Redirect Uri
準備の詳細は、このこのページに参考してください:
https://developers.google.com/identity/protocols/OpenIDConnect?hl=ja
FlaskでGoogleログインを実装する
最低限の機能を実現するコードを実装してみます。
フォルダストラクチャー:
-- requirements.txt -- index.py -- templates |-- login.html |-- index.html
index.py
ポイントはcallback関数。 Google Sign-Inは、callback関数のURIを叩いて、コードを返します。
from flask import Flask, render_template, request import requests import logging logging.basicConfig(level=logging.DEBUG) app = Flask(__name__) @app.route('/login') def login(): return render_template("login.html") @app.route('/oauth/redirect') def callback(): client_id = "your_client_id" client_secret = "your_client_secret" code = request.args["code"] url = "https://www.googleapis.com/oauth2/v4/token" headers = {'Content-Type': 'application/x-www-form-urlencoded'} form = dict(code=code,client_id=client_id, client_secret=client_secret,redirect_uri='http://localhost:5000/oauth/redirect',grant_type='authorization_code') # codeとclient_secretと合わせて、AccessTokenを請求 resp = requests.post(url, headers=headers, data=form) # access_tokenを取得 access_token = resp.json()['access_token'] # access_tokenを使ってリソースを獲得 resp = requests.get('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={access_token}'.format(access_token=access_token)) logging.info(resp.json()) email=resp.json()['email'] # validate the email, if on whitelist, etc. return render_template("index.html", email=email) if __name__ == '__main__': app.run()
templates/login.html
ポイントは渡すのパラメタで、client_id、redirect_uri、scopeのところ、適当に切り替えすることです。 scopeの設定について、Googleのドキュメントに参照してください:
https://developers.google.com/identity/protocols/OpenIDConnect?hl=ja#scope-param
<h1>hello</h1> <a href="https://accounts.google.com/o/oauth2/auth?client_id=your_client_id&redirect_uri=http://localhost:5000/oauth/redirect&response_type=code&scope=openid%20email">グーグルで認証</a>
templates/index.html
<h1>hello</h1> {{email}}
引用
Final: OpenID Connect Core 1.0 incorporating errata set 1
OAuth 2.0の代表的な利用パターンを仕様から理解しよう - Build Insider
OpenID Connectユースケース、OAuth 2.0の違い・共通点まとめ - Build Insider
Using OAuth 2.0 to Access Google APIs | Google Identity Platform
OpenID Connect | Google Identity Platform | Google Developers
確率と統計学のまとめ「1」:基礎知識
要約
統計検定を受ける機会で、確率論と統計学を勉強しました。勉強のときの要点と経験をまとめます。内容が多いため、複数の分けて書きます。
内容はこの久保川さんのこの本に従って、メモしました(超分かりやすくて、おすすめです):
現代数理統計学の基礎 (共立講座 数学の魅力 11)久保川 達也(楽天ブックス)
統計学のための数学入門30講 (科学のことばとしての数学) 永田靖(楽天ブックス)
本記事の内容概要
本文は確率論の基礎概念をまとめます。
確率論の基礎概念の用語集や常用記号、以下で紹介します。この基礎概念は、確率の言葉として、後ほどの記事で繰り返し使ってるから、非常に重要かなと思います。
確率論と統計学は、本文で紹介した概念から発展した理論なので、言葉をきちんと覚えたら、後の勉強に対して非常に役に立つと思います。
記事のスタイル
基本的に、以下のフレームワークに従って紹介します:
概念(What) → 背景(Why) → 応用(How)
- 定義と基本の公式は、概念部分で紹介します。
- その定義と公式の説明は、背景部分で紹介します。
- 定義の用途と関連は応用部分で紹介します。
そして、常に 結論 → 説明 というフローに従っています。
基礎概念
試行:不確からしさを伴う実験。
全事象、標本空間、:試行によって起こりうるすべての結果。集合として捉える。例えば、1回サイコロを投げることの点数なら、
事象:起こりうる結果の集まり。事象も集合として捉える。例えば、1回サイコロを投げることの点数なら、点は奇数の事象は 。
集合族:事項の集合、すなわち の部分集合からなる集合を集合族という。
(事項は集合だから、集合族は集合の集合)
可測集合族:次の三つの性質を満たす集合族は可測集合族といい:
- (1)
- (2)
- (3)
説明:集合の概念と記号の説明は略。集合
確率: 試行の確からしさを数学的に記述したもの。
可測集合族 の元を可測集合といい。可測集合Aに対して、実数を対応させる関数 で、次の三つの性質を満たすものを確率という:
- (1)すべての に対して
- (2)
- (3) が互いに排反であるとき、 が成り立つ
確率変数:事項を実数値で表示すること。と表す。
例:3回振ったサイコロの目の和
確率(累積)分布関数:確率変数が以下の値となる確率をの関数とみたものを分布関数といい。
確率(累積)分布関数になるための必要十分条件:
- (1)
- (2) はxの非減少関数である
- (3) は右連続関数である
確率(密度)関数:離散変数のとる各値に対し、その確率を確率関数といい 連続変数の場合に分布関数の微分を確率密度関数といい。
確率密度関数と確率分布関数の関係:
関数g(X)の期待値:
平均値:関数の期待値はXの平均値といい。
Xの平均値:
分散: 関数 の期待値は分散といい。
以下の計算式はよく使ってる、なぜなら、確率母関数と積率母関数から簡単に計算できるから。
確率関数のモーメント(積率):確率変数のべき乗に対する期待値で与えられる特性値。
は確率のk次モーメントといい。
は に関するのk次モーメントといい。
は確率のk次モーメントといい。
階乗モーメント
確率母関数:確率変数Xの確率母関数は
積率(モーメント)母関数: 確率変数 の積率母関数は ]
特性関数: 確率変数 の特性関数は ]
確率変数の変換:確率変数XをY=g(X)に変換した時Yの分布をXの分布から導くことを考えます。
定義の補充説明
確率母関数、積率母関数と特性関数の説明
いきなりこの3つの概念が出てきて、驚いた可能性がある。自分の認識に基づいて、この3つの概念を説明します。
まず、名前を説明します。この理解は、数学の言語から考えると、覚えやすいかなと思います。
数学において、母関数 は、数列に関する情報を内包した係数を持つ、形式的冪級数である。なので:
確率母関数 という名前は、その関数 から確率 を生成することができるから。
積率母関数 から、その関数 から確率分布関数 の積率を生成することができる。
特性関数 という名前は、この関数を分かれば、確率分布を確定できる、というニュアンスがあります。
確率母関数から確率を求める
はsに関する関数がわかる。
なので:
確率母関数から確率を生成できることがわかる。
確率母関数から階乗モーメントを求める
]
なので
]
k次階乗モーメントは で与えられることがわかる
積率母関数から積率を求める
積率母関数という名前は、 から積率を生成することができるから。
用途
母関数、積率母関数と特性関数から確率、平均、積率を求める
詳細は後の常用確率関数に参照。
特性関数から確率分布の一致と収束を判別する
定理:特性関数と確率分布が1対1に対応すること: の連続点 a,b(a<b)に対して、
が成り立つ。
つまり、二つの確率変数XとYの特性関数 と に対して, がすべてのtで成り立つとき、すべての uに対して、 が成り立つ。
特に のときには が成り立つ。
の分布は の特性関数の極限に対応する
定理:確率変数の列 の特性関数
となる特性関数 に収束すると仮定する。この時 に対応する分布関数を とすると、 のすべての連続点xで、
が成り立つ。
レファレンス
現代数理統計学の基礎 (共立講座 数学の魅力 11)久保川 達也(楽天ブックス)