привет, у меня есть случай, когда по истечении срока действия токена пользователя пользователь не переключается на страницу loginPage, хотя я установил его здесь. как решить эту проблему спасибо.
я установил его на заставке, если токен не равен нулю, затем перейдите на главную страницу, а если токен равен нулю, перейдите на страницу входа. но когда срок действия токена истекает, он все еще остается на главной странице
Future<void> toLogin() async {
Timer(
const Duration(seconds: 3),
() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString(Constant.token);
Navigator.pushReplacementNamed(
context,
token != null ? AppRoute.mainRoute : AppRoute.loginRoute,
arguments: token,
);
},
);
}
и функция при входе пользователя
CustomButtonFilled(
title: 'Login',
onPressed: () async {
final prefs =
await SharedPreferences.getInstance();
prefs.setString(Constant.token, '');
if (nimController.text.isEmpty ||
passwordController.text.isEmpty) {
showError('NIM/Password harus diisi');
} else {
setState(() {
isLoading = true;
});
User? user = await userProvider.login(
nimController.text,
passwordController.text);
setState(() {
isLoading = false;
});
if (user == null) {
showError('NIM/Password tidak sesuai!');
} else {
userProvider.user = user;
Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(route) => false,
);
}
}
},
),
и этот вызов апи
Future<User?> login(String nim, String password) async {
String url = Constant.baseURL;
try {
var body = {
'username': nim,
'password': password,
};
var response = await http.post(
Uri.parse(
'$url/login_mhs',
),
body: body,
);
if (response.statusCode == 200) {
final token = jsonDecode(response.body)['data']['access_token'];
//Ini mulai nyimpen token
await UtilSharedPreferences.setToken(token);
print(token);
// print(await UtilSharedPreferences.getToken());
return User.fromJson(jsonDecode(response.body));
} else {
return null;
}
} catch (e) {
print(e);
throw Exception();
}
}
я думаю, вам нужно создать один базовый класс API, где вы можете обрабатывать все ответы API от одного класса и устанавливать условие для кода состояния, если вы получаете код состояния 401 (истечение срока действия токена), затем перейдите к экрану входа в систему. это упростит вашу работу с каждого экрана или API, вам не нужно каждый раз делать такой код.
Я обновил, как мне решить эту проблему?
Если ваша функция истечения сеанса имеет некоторый предопределенный интервал или логику, вам необходимо реализовать ее на экране-заставке, и на ее основе вы можете перемещаться по пользователю дальше. В противном случае вы хотите обработать его в ответе API, только если у вас есть условие добавления для statusCode 401.
checkSessionExpire(BuildContext context)
if (response.statusCode == 200) {
//SuccessWork
} else if (response.statusCode == 401) {
//SessionExpire
} else {
return null
}
}
Вы должны передать BuildContext в качестве параметра функции, чтобы использовать его, я обновил код. Пожалуйста, проверьте.
В вашей функции входа в систему вы должны передать buildContext. В моем коде checkSessionExpire — это имя функции. Удалите его из своего кода и добавьте контекст в функцию входа в систему. т. е. Future<User?> логин (String nim, String password, контекст BuildContext)
Хорошо, передайте контекст туда. ожидание userProvider.login(nimController.text, passwordController.text, контекст)
результат все тот же, когда срок действия моего токена истекает, он не переходит на страницу loginPage
Отследите ответ, вы получаете код ответа 401? Если да, добавьте какой-нибудь журнал, если условие, чтобы проверить, удовлетворяет ли эта строка кода условию или нет. Затем добавьте свой код маршрутизации в условие if else - else if (response.statusCode == 401) { // здесь добавьте журнал }
как, я немного запутался здесь
с помощью оператора печати или точек останова вы можете легко отлаживать статус ответа и строки кода,
Я пробовал, результат 401, не авторизован, и страницы не перемещаются.
вы можете просто создать свой собственный HTTP-клиент с помощью Dio и добавить Interceptor для автоматической регенерации idToken, если срок его действия истек, с использованием данного refreshToken.
Клиент Http выдает ошибку, если срок действия refreshToken также истекает.
В этом случае просто перейдите к экрану входа.
Полный код для добавления перехватчика и создания собственного HTTP-клиента приведен ниже.
import 'package:dio/dio.dart';
import '../utils/shared_preference.dart';
class Api {
static Dio? _client;
static Dio clientInstance() {
if (_client == null) {
_client = Dio();
_client!.interceptors
.add(InterceptorsWrapper(onRequest: (options, handler) async {
if (!options.path.contains('http')) {
options.path = 'your-server' + options.path;
}
options.headers['Authorization'] =
'Bearer ${PreferenceUtils.getString('IdToken')}';
return handler.next(options);
}, onError: (DioError error, handler) async {
if ((error.response?.statusCode == 401 &&
error.response?.data['message'] == "Invalid JWT")) {
if (PreferenceUtils.exists('refreshToken')) {
await _refreshToken();
return handler.resolve(await _retry(error.requestOptions));
}
}
return handler.next(error);
}));
}
return _client!;
}
static Future<void> _refreshToken() async {
final refreshToken = PreferenceUtils.getString('refreshToken');
final response = await _client!
.post('/auth/refresh', data: {'refreshToken': refreshToken});
if (response.statusCode == 201) {
// successfully got the new access token
PreferenceUtils.setString('accessToken', response.data);
} else {
// refresh token is wrong so log out user.
PreferenceUtils.deleteAll();
}
}
static Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {
final options = Options(
method: requestOptions.method,
headers: requestOptions.headers,
);
return _client!.request<dynamic>(requestOptions.path,
data: requestOptions.data,
queryParameters: requestOptions.queryParameters,
options: options);
}
}
Dio client = Api.clientInstance();
var resposne = (hit any request);
if (error in response is 401){
//it is sure that 401 is because of expired refresh token as we
//already handled idTokoen expiry case in 401 error while
//adding interceptor.
navigate to login screen for logging in again.
}
Пожалуйста, примите решение, если оно решает вашу проблему.
В этом случае вам также необходимо сохранить дату истечения срока действия токена в общих настройках и проверить на заставке, является ли эта дата в прошлом или нет, и если эта дата в прошлом, вы перенаправляетесь на вход в систему или на главный экран. Основная причина этого заключается в том, что даже если срок действия вашего токена истек, он не будет удален из общего предпочтения сам по себе, и вам необходимо удалить его вручную, если вы получите 401 или несанкционированный ответ от любого API.