토큰 저장
MisskeyAuthManager는 여러 계정의 토큰을 저장하고 활성 계정을 관리합니다. 저장은 TokenStore 인터페이스를 통해 이루어지며 기본 구현은 SecureTokenStore입니다.
계정 관리
final auth = MisskeyAuthManager.defaultInstance();
// 토큰
final current = await auth.currentToken(); // 활성 계정. 없으면 null
final specific = await auth.tokenOf(key); // 지정한 계정. 없으면 null
// 계정
final accounts = await auth.listAccounts();
await auth.setActive(key);
final active = await auth.getActive();
await auth.clearActive();
// 로그아웃
await auth.signOut(key); // 한 계정의 토큰 삭제
await auth.signOutAll(); // 모든 계정의 토큰 삭제
로그아웃은 기기에 저장된 토큰만 삭제합니다. 서버에서 토큰을 폐기하지는 않습니다.
시간 초과
MisskeyAuthManager.defaultInstance()는 기본 시간 초과(연결 10초, 전송 및 수신 각각 20초)를 사용합니다. 변경하려면 MisskeyAuthManager를 직접 구성하세요. MisskeyAuthManager의 시간 초과는 자체 /api/i 요청에만 적용되므로 각 클라이언트에도 전달해야 합니다.
const timeout = Duration(seconds: 30);
final auth = MisskeyAuthManager(
miauth: MisskeyMiAuthClient(receiveTimeout: timeout),
oauth: MisskeyOAuthClient(receiveTimeout: timeout),
store: const SecureTokenStore(),
receiveTimeout: timeout,
);
각 생성자는 connectTimeout, sendTimeout, receiveTimeout을 받습니다. dio도 전달할 수 있습니다. 클라이언트는 전달된 Dio에도 시간 초과 인수를 적용하지만, MisskeyAuthManager는 dio를 전달받으면 시간 초과 인수를 무시합니다. 이 경우 Dio에서 직접 설정하세요.
모델
class AccountKey {
final String host; // 예: 'misskey.io'
final String accountId; // 해당 서버의 사용자 ID
}
class StoredToken {
final String accessToken;
final String tokenType; // 'MiAuth' 또는 'OAuth'
final String? scope; // OAuth만 해당
final Map<String, dynamic>? user;
final DateTime? createdAt;
}
class AccountEntry {
final AccountKey key;
final String? userName;
final DateTime? createdAt;
}
사용자 ID는 서버 내에서만 고유하므로 AccountKey는 호스트와 사용자 ID를 조합합니다. 호스트는 설정에 전달한 문자열 그대로 저장되므로, 같은 서버에는 항상 같은 형식(예: 소문자 misskey.io)을 사용하세요. 기존 AccountKey에 토큰을 저장하면 이전 토큰을 대체합니다.
TokenStore
토큰을 다른 곳에 저장하려면 TokenStore를 구현해 MisskeyAuthManager에 전달합니다.
abstract class TokenStore {
Future<void> upsert(AccountKey key, StoredToken token);
Future<StoredToken?> read(AccountKey key);
Future<List<AccountEntry>> list();
Future<void> delete(AccountKey key);
Future<void> clearAll();
Future<void> setActive(AccountKey? key);
Future<AccountKey?> getActive();
}
SecureTokenStore
SecureTokenStore는 flutter_secure_storage로 토큰을 저장합니다. iOS에서는 키체인, Android에서는 Keystore를 사용합니다. 저장 옵션을 변경하려면 직접 생성한 FlutterSecureStorage를 전달하세요. misskey_auth는 이 클래스를 재내보내지 않으므로 flutter_secure_storage를 종속성에 추가하고 import해야 합니다.
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const store = SecureTokenStore(
storage: FlutterSecureStorage(/* 선택적 옵션 */),
);
동시성
- 쓰기 작업(
upsert,delete,clearAll,setActive)은 같은 isolate 안에서 인스턴스가 달라도 한 번에 하나씩 실행됩니다. 동시에 써도 인덱스에서 계정이 사라지지 않습니다. - 읽기는 차단되지 않습니다. 또한
upsert후setActive와 같은 일련의 작업은 원자적으로 처리되지 않습니다. - 다른 isolate 또는 프로세스의 쓰기 작업과는 상호 배제하지 않습니다.
clearAll이 삭제하는 항목
clearAll은 스토어 인덱스에 나열된 계정, 인덱스 자체, 활성 계정 설정을 삭제합니다. 저장 영역 전체를 열거하지는 않습니다. Android에서는 항목 하나의 복호화에 실패해도 readAll이 저장 영역 전체를 지울 수 있기 때문입니다. 따라서 이전 버전에서 인덱스에 등록되지 않은 채 남은 토큰은 삭제되지 않습니다.
공유 저장 영역
기본 SecureTokenStore는 기본 저장 영역을 사용하며, 앱의 다른 코드도 같은 영역을 사용할 수 있습니다. flutter_secure_storage 11에서는 resetOnError가 기본으로 활성화되어 있어 저장 영역 오류에서 복구할 때 해당 영역의 다른 값도 삭제될 수 있습니다. 같은 저장 영역에 다른 데이터를 보관한다면 설정을 확인하세요. flutter_secure_storage 변경 기록도 참조하세요.