FlutterでHttpClientのDioを使用して認証情報などをクッキー（Cookie）に持たせる方法

# はじめに

自前で作成したバックエンドの認証機能をRest APIで呼び出して、その認証情報をFlutterでどうやって利用するかを考えた時に、クッキー（Cookies）を利用しようとなったので、FlutterではCookiesはどうやったら実装できるのか調べました
FlutterでのCookieの利用方法についてのナレッジを記載していきます


# Cookie初歩形

まずFlutterでCookiesを利用したい場合はデフォルトクッキーが備わっています

Cookie利用の初歩形
```dart
import 'dart:io';

Cookie cookie = Cookie('name', 'value')
```

しかしこれだけではただのマップ型のインスタンス感があり、実用としては使いづらいです


# 外部パッケージ導入

通常Cookiieを使用したい場合はAPIを利用する場面であるので、中国製のDioというHttpClientのパッケージを利用します
また、DioとCookieをいい感じで利用できるようにしてくれるパッケージCookieJarやCookieManagerもインストールします

https://pub.dev/packages/dio

https://pub.dev/packages/cookie_jar

https://pub.dev/packages/dio_cookie_manager


pubspec.yaml
```yaml
dependencies:
  dio: ^4.0.4
  cookie_jar: ^3.0.1
  dio_cookie_manager: ^2.0.0
  path_provider: ^2.0.9
```

path_providerはdio_cookie_managerの説明書きにクッキーを永続化するなら入れろと書かれていました
永続化する場合はどうやらストレージにCookieを保管するためにパーミッションの設定が必要なようです
デフォルトでは読み取り専用になっているので書き込みもできるように設定が必要な模様

# Cookie基本形その1

HttpClientのDioを利用したCookieの使い方としては以下の形が基本形その1となります
```dart
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';


final Uri _uriHost = Uri.parse('ホスト');

Future auth() async {
   Dio dio = Dio();
   List<Cookie> cookies = [];

    dio.options.baseUrl = _uriHost.toString();
    dio.options.connectTimeout = 5000;
    dio.options.receiveTimeout = 3000;
    dio.options.contentType = 'application/json';

    try {
      CookieJar cookieJar = CookieJar();
      cookieJar.saveFromResponse(_uriHost, _cookies);
      dio.interceptors.add(CookieManager(cookieJar));
      final response = await dio.post(
          '/authen/jwt/create',
          data: {
            'email': email,
            'password': password,
          }
      );
      cookies = [ ..._cookies, Cookie('access_token', response.data['access']) ];
      List<Cookie> result = await cookieJar.loadForRequest(_uriHost);
      print(result);
    } catch(error) {
      message = '正しいEメールとパスワードを入力してください';
      print(error);
    }
  }
```


# Cookie永続化

上の基本形のクッキーは永続的なインスタンスではないので、Cookiesをほかのメソッドやクラスからなどでも使いたいときはPersistCookieJarを使う
こちらがCookieを一番使うことを最も想定された使い方だと思います

認証情報をCookieへ格納して永続化する基本形
login.dart
```dart
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';

import 'package:path_provider/path_provider.dart';


final Uri _uriHost = Uri.parse('http://ホスト'); // http://10.0.2.2:8000


Future auth() async {
    Dio dio = Dio();
    List<Cookie> cookies = [];

    dio.options.baseUrl = _uriHost.toString();
    dio.options.connectTimeout = 5000;
    dio.options.receiveTimeout = 3000;
    dio.options.contentType = 'application/json';

    try {

      Directory appDocDir = await getApplicationDocumentsDirectory();
      String appDocPath = appDocDir.path;
      PersistCookieJar cookieJar = PersistCookieJar(storage: FileStorage(appDocPath+"/.cookies/"));

      cookieJar.saveFromResponse(_uriHost, cookies);
      dio.interceptors.add(CookieManager(cookieJar));

      final response = await dio.post(
          '/authen/jwt/create',
          data: {
            'email': userModel.email,
            'password': password,
          }
      );

      cookies = [ ...cookies, Cookie('access_token', response.data['access']) ];
      cookieJar.saveFromResponse(_uriHost, cookies);

      List<Cookie> cookieList = await cookieJar.loadForRequest(_uriHost); // 格納されたクッキーを確認しているだけの処理
      print(cookieList);
    } catch(error) {
      message = '正しいEメールとパスワードを入力してください';
      print(error);
    }
  }
```

ここで格納されたクッキーのインスタンスは以下のようにするとほかのメソッドやクラスなどから参照できるようになる
これにより一度ログインしたときの認証情報を他のクラスで共有することができて、Cookieを便利に使えるようになった

# 永続化したCookie情報を他のメソッドやクラスなどから読み込む方法

上記で格納したCookie上に格納されている認証情報は以下のようにして取り出して利用することができる

例: fetch.dart
```dart
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:path_provider/path_provider.dart';


final Uri _uriHost = Uri.parse('ホスト'); // http://10.0.2.2:8000


Future fetch() async {
    final Dio dio = Dio();

    Directory appDocDir = await getApplicationDocumentsDirectory();
    String appDocPath = appDocDir.path;
    PersistCookieJar cookieJar = PersistCookieJar(storage: FileStorage(appDocPath+"/.cookies/"));
    dio.interceptors.add(CookieManager(cookieJar));
    print(await cookieJar.loadForRequest(_uriHost));

    // TODO fetchの処理
    final response = await dio.get(
          '/list-data',
          // Cookiesの認証情報をHeaderに持たせるetc........
          // options: Options(
          //  headers: {
          //    'Authorization': 'JWT ${cookieList.first.value}',
          //  },
          // ),
      );
}
```