Webアプリケーション開発において、とても重要な技術である「セッション」という仕組みについて、よく理解できていなかったのでまとめてみました。
まずはWebの設計思想から
Webをシンプルかつ使いやすいものにするための設計思想としてRESTを採用しています。 以下、RESTを構成している6つのアーキテクチャスタイル
※その他、「Web」についての知識に関しては、こちらを参照
アーキテクチャスタイル | 内容 |
---|---|
クライアント/サーバ | クライアントがサーバにリクエストを送り、サーバがそれに対してレスポンスをする |
ステートレスサーバ | サーバ側でアプリケーション状態を持たない。クライアントが一度出した処理を記憶してない |
キャッシュ | クライアントとサーバの通信回数と量を減らす。クライアントが取得したリソースを使い回し |
統一インターフェイス | インターフェイスを固定する。(例:HTTPメソッドは8つで統一する) |
階層化システム | システムを階層に分離する |
コードオンデマンド | プログラムをクライアントにダウンロードして実行する(例:JavaScriptはインストール不要) |
この中でも、今回のセッションと切っても切り離せないのが、2つ目の「ステートレスサーバ」というアーキテクチャスタイル。Web(サーバ)はクライアントが出した過去のリクエストについて覚えていません。これはWeb(サーバ)からすると、リクエスト内容を覚える必要がない(覚えるためのメモリを用意しておく必要がない)ので、その分リクエスト処理に集中できるという点で大きなメリットがあります。しかし、ユーザー(クライアント)からすると、Webサービスの利用時に不便に働きます。
例えば、あるWebサービスに会員登録をして、ログインフォームにユーザー名とパスワードを入力してログインしたとします。すると、ログインが成功してサービスのトップ画面が表示されます。そして、別のページを表示させようとすると・・・、
Web(サーバ)はユーザーがログインしたということを覚えていないので、ログインフォームに戻り、ユーザーに対して再度ログインするよう要求します。ユーザーからすると、何度もログインしないといけないので、めちゃくちゃ不便です。
そこで、こういった問題を解決する仕組みとして利用されるのが、セッションという仕組みです。
セッションという仕組み
「セッション」という言葉の意味
セッションという言葉の意味は広く、様々な文脈で使われます。
②一時的な情報の格納先
③ユーザーがログインしてからログインするまでの期間
セッション(session)とは?
セッション(session)は、ハッシュ(Hash)オブジェクトです。なので、あるキーに対する値としてデータを格納します。
1 |
session = {"fruits": "orange", "vegetable": "tomato", ...} |
セッション(session)をどのように使うのか?
このセッション(session)を利用して、ログインユーザーの情報を保存することで、ステートレスというWebのアーキテクチャスタイルのデメリットを解消します。
1 |
session = {"url": "https://chopesu.com/blog/123", "user_id": "1", "contents": "sample..."} |
具体的には、上記のようにセッション(session)にユーザー情報を格納し、ユーザーからのリクエスト時にこのセッション情報をサーバーに読み込ませることで、サーバーに同一ユーザーからのリクエストであることを認識させます。
どのようにしてサーバーにセッション情報を読み込ませるのか?
セッション(session)には個人情報が多く格納されているので、セキュリティのことを考えて慎重に扱う必要があります。では、どのようにしてサーバにこのセッション情報を安全に読み込ませるようにするのか?
それにはいくつかの方法があります。
・Cookieを利用する
・Redisを利用する
・データベースを利用する
・memcachedを利用する
・memoryを利用する 等々
Cookieを利用して、セッション情報をサーバーに読み込ませる
Cookieとは?
Cookieとは、ブラウザにデータを保存すること、及びその保存場所のことです。今のWebサービスでは無くてはならない存在になったCookieですが、データを保存できる容量はとても少なく、4KBまでしかデータを保存することができません。日本語で1000〜2000文字程度、英語でも最大で4000文字程度の容量です。
Cookieは、保存されたデータを全てのリクエストに含めて送るという特徴があります。具体的には、HTTPリクエストメッセージのcookieヘッダー内にデータを乗せてリクエストを送っています。
Cookieへのデータの書き込み方法
Cookieへのデータの書き込み方法は3つあります。
①HTMLタグに書き込む
②JavaScriptに書き込む
③サーバーからクライアントへのレスポンスに含める
⇒具体的には、HTTPレスポンスメッセージのset-cookieヘッダーにデータを保管することで、クライアント(ブラウザ)にデータを送り、ブラウザ側でCookieに保存します。
これら3つの方法のうち、今回は③を利用した場合を説明していきます。
RailsではCookieにどのようにして、セッション情報を保存しているのか?
Railsでは、クライアントからのリクエストに対するレスポンスの際に送られるCookieオブジェクトにセッション(session)情報を暗号した文字列を保存しています。これだけだと分かりにくいので、一つ一つ見ていきます。
セッション(session)情報を安全に扱うために暗号化
まずCookieオブジェクトについてですが、このオブジェクトはハッシュオブジェクトです。なので、あるキーに対する値としてデータを保存します。これは、開発者ツールを使えば簡単に見ることができます。
Chromeであれば、開発者ツールのNetworkを開いて、通信内容をクリックするとCookiesというタブが出てくるので、そこをクリックすれば、そのリクエスト/レスポンスでやりとりされたCookieオブジェクトを見ることができます。
例えば、下記の画像はQiitaにアクセスした時のCookieオブジェクトのキーと値です。
とても分かりやすく「session」と書いてありますね。ここにsessionが保存されている予感がします。これがCookieオブジェクトのキーです。その右に書いてある文字列が値です。
1 |
cookie{"_qiita_login_session": "YVVUY・・・・・・"} |
では、この値(文字列)は何を示しているのか?
実はこれがセッション(session)の情報です。
Railsでは、セッション(session)オブジェクトに保存された情報は自動で暗号化されます。この役割を一部担っているのが、secret_key_baseやcredentials.yml.encです。
1 |
session = {"url": "https://chopesu.com/blog/123", "user_id": "1", "contents": "sample..."} |
このセッション(session)オブジェクトの情報が暗号化された結果、
1 |
"YVVUY・・・・・・" |
こうなったという訳です。
なので、先ほどのCookieオブジェクトは_qiita_login_sessionというキーに対する値として暗号化されたセッション(session)情報を格納していたということです。
HTTPレスポンスに乗せてセッション(session)情報をブラウザへ
これで、セッション(session)の情報を安全に運ぶ準備が整いました。Cookieオブジェクトは、HTTPレスポンスメッセージのset-cookieヘッダーに格納してブラウザにセッション(session)の情報を送ります。これも先程と同様で、開発者ツールを使ってHeadersというタグをクリックして、Response Headersを見れば記載されています。
こうして、ブラウザに無事にセッション(session)情報を送ることができました。こうしてレスポンスを受けたブラウザはset-cookie内に格納されているセッション(session)情報を読み込み、Cookieに保存します。
セッション(session)情報をリクエストに含めて送る
ブラウザは、HTTPリクエストメッセージのcookieにCookieの情報を含めてサーバーにリクエストを送ります。これは保存されたデータを全てのリクエストに対して送るというCookieの特徴を利用しています。リクエストを受けたサーバーは、cookieに含まれているセッション(session)の情報の中から、ログインユーザーの情報を読み込むことで、リクエストを送ってきたユーザーが前回と同一ユーザーであることを認識します。
これも先程と同様で、開発者ツールを使ってHeadersというタグをクリックして、Request Headersを見れば記載されています。
このようにして、セッションを利用して、ログインユーザーの情報を保存することで、ステートレスというWebのアーキテクチャスタイルのデメリットを解消しています。
私もこのセッションの仕組みをよく理解していなかったので、未経験エンジニアの方はこの仕組みを理解できていると、Web技術に対してより理解が深まるのではないかと思います。
実際にこのセッションの仕組みを利用してログイン機能を実装する方法については、
下記の記事で紹介していますので、是非ご覧ください!
セッションの仕組みを利用して、deviseを使わずにログイン機能を実装してみた