- Webエンジニア
- アウトバウンド営業
- Webエンジニア(経験者)
- 他17件の職種
- 開発
- ビジネス
※弊社エンジニアの記事になります。
きっかけ
業務でrails APIの環境に出会い、railsの勉強がてら個人で同じ構成で何か作ってみようとした時に、APIでの認証へ具体的な理解が浅いなと思ったので、調べてみることにしました。
この記事では、APIでの認証の基本的な仕組みを理解した上で簡単な実装ができるまでを目指します。
認証とリソースアクセスのフロー
さっそくですが、APIサービスでの認証と認証後のリソースへのアクセスフロー(一例)を図にしてみました。
- メールアドレスとパスワードを送信する
- サーバ側でユーザーの存在を検証する
- 検証に問題なければ、クライアントにトークンを返す
- クライアントはサーバから送られてきたトークンをリクエストヘッダーに含めてリクエストを送る
- サーバはトークンをデコード・検証し、ユーザーの確認が取れた場合、リソースへのアクセスを行う
- リクエストに対するレスポンスを返却する
(RESTfulを意識した)APIはステートレスであることが望ましく、各通信が独立している必要があります。つまり、サーバ側はそのリクエストが誰のものか特定する情報(ここではトークン)を保持しません。
比較としてセッション方式のフローを図にしてみました。
この方式だとサーバはセッションという形でユーザーの情報を保持していますが、上のトークン方式の場合、サーバーはトークンを払い出すだけでトークン自体の管理はしていません。
サーバ側で状態を持たずに認証を可能にする仕組みがトークンベースの認証になります。
認証処理の鍵は「トークン」
ここまでで、トークンを使ったAPIの認証フローはイメージできたと思います。
ここからは、トークン自体に焦点を当てていきます。
JWT
APIの認証で一般的に使われるトークンには規格が存在します。それがRFC7519で定義されている「JWT」です。
JWTは「JSON Web Token」の略で文字通りJSON形式で表現されたトークンです。JWTは大きく3つの構造から成り立ちます。
- ヘッダー
- ペイロード
- 署名
1つずつ見ていきましょう。
ヘッダー
トークンの処理方法に関するメタデータを含みます。具体的にはトークンタイプや署名生成に使われるアルゴリズムを指定します。
{
"alg": "HS256",
"typ": "JWT"
}
ペイロード
トークンの本体で、ユーザー識別情報、有効期限など、様々なクレームを含みます。
ここでのクレームとは1つの「キー:値」1セットのイメージで大丈夫です。
JSONのキーが「クレーム名」、値が「クレーム値」という表現がされます。
ペイロード内のクレームには3種類あります。
Registered Claim Name
RFC7519で予約されているクレーム名です。
IANAの”JSON Web Token Claims”で定義されているクレーム名の内、特に限定して指定されています。
具体的には以下になります。
- iss(発行者)
- sub(件名)
- aud(オーディエンス)
- exp(有効期限)
- nbf(有効になる日時)
- iat(発行日時)
- jti(JWTを一意に特定する値)
Public Claim Name
IANAの”JSON Web Token Claims”で定義されているクレーム名。
JWT使用者間で共有される情報(=外部サービスでも使われ得る情報)が該当します。
Private Claim Name
特定のアプリケーション間でのみ意味を持ち、一般に公開しないものが該当し、一般的にはこれを利用します。
ペイロードの具体例は以下になります。
{
"jti": "92f46647-90a2-4174-bca9-27d7f69a8fb7",
"exp": 1485320878,
"user_id": 123,
"email": "test@example.com
}
署名
署名は
- 誰がそのJWTを発行したか
- ヘッダーとペイロードは改ざんされていないか
を保証するために付け加えられます。
署名生成の流れは以下のイメージです。
- ヘッダー・ペイロードをBase64 URLエンコード
- それぞれを「.」で連結
- 連結文字列をヘッダー「alg」の方式でハッシュ化
- ハッシュ化した文字列をサーバの秘密鍵で署名
- 署名した値をBase64 URLでエンコード
JWTの生成とセキュリティ面の考慮
ここまで見てきたJWTの3つの構造はエンコードされると「.」で繋いだ文字列になります。
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAwNTQzOTB9.uIALzjUXmOdsFy0vMetZivYoWq5haiufCKeeNQYzFWw
.区切りで「ヘッダー」「ペイロード」「署名」の構造となっており、この文字列をデコードするとJSON形式になります。
ここでのエンコードとは、URLにくっつけても大丈夫な形式Base64 URLというフォーマットで行われますが、これは暗号化しているわけでなく、単に形式を変えているだけであり、セキュリティ面を考慮するならHTTPSで通信する必要があります。
つまり、署名を利用すると改ざんの検知が可能にはなりますが、JWT自体は丸見えのデータです。
トークン失効戦略
ここまで、トークン認証のフロートJWTの中身について見てきました。
冒頭で、サーバはトークンを生成するが、それ自体を管理しないと述べました。ということは、有効期限切れ以外でトークンを無効化させる方法は自前で用意する必要があります。
そのための方法は複数あり、今回は3つ取り上げます。
ブラックリスト方式
トークンに付与される一意のID「jti」を保存するテーブルを用意し、無効化したいトークンのjtiをテーブルに格納していきます。
このテーブルに保存されているjtiに紐づくトークンは利用できないものとして扱います。
ホワイトリスト方式
ブラックリスト方式とは逆に、許可したいトークンのjtiを保存し、このテーブルに紐づくトークンのみ利用可能とします。
JTI一致方式
ユーザーテーブルのカラムにjti列を生成し、トークン生成時に現在設定されているjtiの値をJWTに含めます。
ログアウト時に、ユーザーテーブルのjtiカラムの値を更新することで、既存トークンが送られてきた際に、一致しないため無効と判断できます。
次回トークンを生成するときは、更新後のjtiの値をトークンに含め、以降ログアウト→ログインで繰り返します。
※この記事ではJTI一致方式で実装していきます。
実装
ここからは実際にruby on railsでAPIの認証を実装していきます。
※前提としてrailsのAPIモードでプロジェクトを作成しているものとします。
…
記事の続きは下のリンクをクリック!
https://rightcode.co.jp/blog/information-technology/rails-api-syain
【2024年卒】新卒採用エントリー開始しました!
特設ページはこちら:https://rightcode.co.jp/recruit/entry-2024
※募集は終了致しました。次回の募集までもうしばらくお待ちください
インターン募集!未経験ok、チャレンジ精神ある方求む
WEBエンジニア:https://rightcode.co.jp/recruit/intern-web-engineer
メディア運営:https://rightcode.co.jp/recruit/intern-media
社長と一杯飲みながらお話しませんか?(転職者向け)
特設ページはこちら: https://rightcode.co.jp/gohan-sake-president-talk
もっとワクワクしたいあなたへ
現在、ライトコードでは「WEBエンジニア」「スマホアプリエンジニア」「ゲームエンジニア」、「デザイナー」「WEBディレクター」「エンジニアリングマネージャー」「営業」などを積極採用中です!
有名WEBサービスやアプリの受託開発などの企画、開発案件が目白押しの状況です。
- もっと大きなことに挑戦したい!
- エンジニアとしてもっと成長したい!
- モダンな技術に触れたい!
現状に満足していない方は、まずは、エンジニアとしても第一線を走り続ける弊社代表と気軽にお話してみませんか?
ネット上では、ちょっとユルそうな会社に感じると思いますが(笑)、
実は技術力に定評があり、沢山の実績を残している会社ということをお伝えしたいと思っております。
- ライトコードの魅力を知っていただきたい!
- 社風や文化なども知っていただきたい!
- 技術に対して熱意のある方に入社していただきたい!
一度、【Wantedly内の弊社ページ】や【コーポレートサイト】をのぞいてみてください。
【コーポレートサイト】https://rightcode.co.jp/
【採用募集】https://rightcode.co.jp/recruit(こちらからの応募がスムーズ)
【wantedlyぺージ】https://www.wantedly.com/companies/rightcode