👋

「actix-web」入門#5 セッション管理v2「actix_redis」

2022/06/06に公開

初めに

セッションについては前回話しました。
しかし、actix-webの「actix-session」はCookieセッションとイコールであることが判明したので独自セッションが必要であると解説しました。
※Cookieセッションのみの世界線だとセッション(アカウント)乗っ取りし放題なので…

そこで詳しく確認してみると「actix-redis::RedisSession」がセッションとイコールであることがわかりました。

今回はredisを使った「actix-redis」を紹介します。

以下の説明をしていきます。

  1. redisの概念
  2. 「actix-redis」の解説
  3. 「actix-redis」の具体例

1 redisの概念

redisはメモリ管理サービスです。
シンプルにメモリ内の変数を管理するサービスと考えて差し支えないと思います。

redisは、メモリで管理する変数の使用期限を決められるのでセッションタイムアウトの概念と一致する感じがします。

redisの特殊な機能として、ポートを開放して、slaveを作ることでメモリ情報をほかのユーザからも確認できる状態になります。いわゆる簡易データベース(メモリ上のものなので永続的でない)です。
※このredisのslave(奴隷)ってやつ個人的に命名しなおしてほしい…

redisのインストールはwslを使います。
※以前触ったときはwindows用のインストーラあったのになくなってて焦った(;^_^A
https://redis.io/docs/getting-started/installation/install-redis-on-windows/

2 「actix-redis」の解説

今回は以下のexampleを解説します。
https://github.com/actix/examples/tree/master/auth/redis-session

ソース確認

フォルダ構成はこんな感じ

ざっくりmain.rsだけ説明します。
ソースはこんな感じです。

main.rs
//! Example of login and logout using redis-based sessions
//!
//! Every request gets a session, corresponding to a cache entry and cookie.
//! At login, the session key changes and session state in cache re-assigns.
//! At logout, session state in cache is removed and cookie is invalidated.
//!
use actix_redis::RedisSession;
use actix_session::Session;
use actix_web::{
    middleware, web,
    web::{get, post, resource},
    App, HttpResponse, HttpServer, Result,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, PartialEq)]
pub struct IndexResponse {
    user_id: Option<String>,
    counter: i32,
}

async fn index(session: Session) -> Result<HttpResponse> {
    ...
}

async fn do_something(session: Session) -> Result<HttpResponse> {
    ...
}

#[derive(Deserialize)]
struct Identity {
    user_id: String,
}

async fn login(user_id: web::Json<Identity>, session: Session) -> Result<HttpResponse> {
    ...
}

async fn logout(session: Session) -> Result<String> {
    ...
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    ...
}

#[cfg(test)]
mod test {
    ...
    #[actix_web::test]
    async fn test_workflow() {
	...
    }
}

リクエストを行うための関数として「index」「do_something」「login」「logout」があります。
各リクエスト処理はcfg(test)を使ってお試しのために作成されているようです。

test_workflowは以下の通りです。

  1. indexに「GET」処理を送ってcookieセッションを取得。
  2. do_somethingにテスト的に「POST」処理を送ってcounterってcookie情報を0→1にする。
  3. do_somethingにテスト的に「POST」処理を送ってcounterってcookie情報を1→2にする。なお、このときのクッキー情報を「cookie_1」とする。
  4. loginに「POST」処理を送ってuser_id「ferris」でセッション開始する。なお、このときのクッキー情報を「cookie_2」とする。
  5. indexに「GET」処理を送ってcookieセッション「cookie_2」を再取得(ユーザ情報を確認)。
  6. クッキー情報「cookie_2」でdo_somethingにテスト的に「POST」処理を送ってcounterってcookie情報を2→3にする。
  7. indexに「GET」処理を送ってcookieセッション「cookie_1」を再取得(ユーザ情報がないのを確認)。
  8. クッキー情報を「cookie_2」でlogoutに「POST」処理を送ってログアウトする。
  9. indexに「GET」処理を送ってcookieセッション「cookie_2」を再取得(ユーザ情報がないのを確認)。

上記のテストではマクロ「assert_eq」と「assert_ne」を使って、逐一counter、user_id合ってるかっていうのを確認しているようです。

動作確認

まず、wsl(Ubuntu)上で「sudo service redis-server start」と打ち、redisサーバを立ち上げます。

「cargo run」でwebサーバを立ち上げます。

上記の実装例だと「cargo test」コマンドからのみformのsubmit(POST送信)できる仕様なので、
新規ターミナルを開いて、「cargo test test」と打ち込んで確認します。

wsl(Ubuntu)から「redis-cli」と打ち込んでredisターミナルを開き、「keys *」でredisで管理している変数を確認します。
繰り返し「keys *」を打っていると、キー「session」に対してセッションが格納されるのが確認できます。

放置しておくと、数秒でセッションタイムアウトします。

セッションタイムアウト後、「keys *」でキーが削除されていることを確認します。

3「actix-redis」の具体例

以下のサイトのようにVue.jsではapiでログイン認証を作るのが一般的なようなので、
「入門#4 CORS」でのソース「backend」をapiと見立ててログイン機能を作ってみます。
https://qiita.com/koduki/items/b4b56a27c6b7406a4ddb

※実装に時間かかりそうなので次に進みます。ごめん。

個人的にelectronやmeteorに触れていたので、マルチプラットホームに対応できる点を加味して夢が広がっています。

次回

exampleの「websocket」を触ってみます。

上記以降は以下のいずれかをやっていく感じです。
・db周りとかの解説
・test周りとかの解説
・tls周りとかの解説

Discussion