Better to solve multi-factor authenticate

This commit is contained in:
LittleSheep 2024-05-01 11:27:48 +08:00
parent 5d79692766
commit 28c0094837
5 changed files with 38 additions and 19 deletions

View File

@ -26,7 +26,7 @@ class AuthProvider extends ChangeNotifier {
DateTime? lastRefreshedAt; DateTime? lastRefreshedAt;
Future<bool> pickClient() async { Future<bool> loadClient() async {
if (await storage.containsKey(key: storageKey)) { if (await storage.containsKey(key: storageKey)) {
try { try {
final credentials = oauth2.Credentials.fromJson((await storage.read(key: storageKey))!); final credentials = oauth2.Credentials.fromJson((await storage.read(key: storageKey))!);
@ -43,7 +43,7 @@ class AuthProvider extends ChangeNotifier {
} }
Future<oauth2.Client> createClient(BuildContext context, String username, String password) async { Future<oauth2.Client> createClient(BuildContext context, String username, String password) async {
if (await pickClient()) { if (await loadClient()) {
return client!; return client!;
} }
@ -92,7 +92,7 @@ class AuthProvider extends ChangeNotifier {
const storage = FlutterSecureStorage(); const storage = FlutterSecureStorage();
if (await storage.containsKey(key: storageKey)) { if (await storage.containsKey(key: storageKey)) {
if (client == null) { if (client == null) {
await pickClient(); await loadClient();
} }
if (lastRefreshedAt == null || DateTime.now().subtract(const Duration(minutes: 3)).isAfter(lastRefreshedAt!)) { if (lastRefreshedAt == null || DateTime.now().subtract(const Duration(minutes: 3)).isAfter(lastRefreshedAt!)) {
await refreshToken(); await refreshToken();

View File

@ -22,7 +22,7 @@ class ChatProvider extends ChangeNotifier {
ChatCallInstance? call; ChatCallInstance? call;
Future<WebSocketChannel?> connect(AuthProvider auth) async { Future<WebSocketChannel?> connect(AuthProvider auth) async {
if (auth.client == null) await auth.pickClient(); if (auth.client == null) await auth.loadClient();
if (!await auth.isAuthorized()) return null; if (!await auth.isAuthorized()) return null;
await auth.refreshToken(); await auth.refreshToken();

View File

@ -61,7 +61,7 @@ class NotifyProvider extends ChangeNotifier {
} }
Future<WebSocketChannel?> connect(AuthProvider auth) async { Future<WebSocketChannel?> connect(AuthProvider auth) async {
if (auth.client == null) await auth.pickClient(); if (auth.client == null) await auth.loadClient();
if (!await auth.isAuthorized()) return null; if (!await auth.isAuthorized()) return null;
await auth.refreshToken(); await auth.refreshToken();

View File

@ -4,6 +4,7 @@ import 'package:provider/provider.dart';
import 'package:solian/providers/auth.dart'; import 'package:solian/providers/auth.dart';
import 'package:solian/router.dart'; import 'package:solian/router.dart';
import 'package:solian/utils/service_url.dart'; import 'package:solian/utils/service_url.dart';
import 'package:solian/widgets/exts.dart';
import 'package:solian/widgets/indent_wrapper.dart'; import 'package:solian/widgets/indent_wrapper.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
@ -63,6 +64,11 @@ class SignInScreen extends StatelessWidget {
}).catchError((e) { }).catchError((e) {
List<String> messages = e.toString().split('\n'); List<String> messages = e.toString().split('\n');
if (messages.last.contains("risk")) { if (messages.last.contains("risk")) {
final ticketId = RegExp(r"ticketId=(\d+)").firstMatch(messages.last);
if (ticketId == null) {
context
.showErrorDialog("requested to multi-factor authenticate, but the ticket id was not found");
}
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
@ -73,7 +79,9 @@ class SignInScreen extends StatelessWidget {
TextButton( TextButton(
child: Text(AppLocalizations.of(context)!.next), child: Text(AppLocalizations.of(context)!.next),
onPressed: () { onPressed: () {
launchUrlString(getRequestUri('passport', '/sign-in').toString()); launchUrlString(
getRequestUri('passport', '/mfa?ticket=${ticketId!.group(1)}').toString(),
);
if (Navigator.canPop(context)) { if (Navigator.canPop(context)) {
Navigator.pop(context); Navigator.pop(context);
} }

View File

@ -2,11 +2,21 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
extension SolianCommonExtensions on BuildContext { extension SolianCommonExtensions on BuildContext {
Future<void> showErrorDialog(dynamic exception) => showDialog<void>( Future<void> showErrorDialog(dynamic exception) {
String formatMessage(dynamic exception) {
final message = exception.toString();
if (message.trim().isEmpty) return '';
return message
.split(' ')
.map((element) => "${element[0].toUpperCase()}${element.substring(1).toLowerCase()}")
.join(" ");
}
return showDialog<void>(
context: this, context: this,
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
title: Text(AppLocalizations.of(this)!.errorHappened), title: Text(AppLocalizations.of(this)!.errorHappened),
content: Text(exception.toString()), content: Text(formatMessage(exception)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.pop(ctx), onPressed: () => Navigator.pop(ctx),
@ -16,3 +26,4 @@ extension SolianCommonExtensions on BuildContext {
), ),
); );
} }
}