我不想在每次查询时检查我的JWT令牌是否过期,而是只在main
中首次初始化应用程序时检查它,然后每55分钟自动刷新一次。
这是我在Widget树顶部调用的刷新函数;
void main() async {
await refreshToken()
};
这是refreshToken代码;
Future<String?> refreshToken() async {
String? refreshToken = await getCryptRefresh(); //gets refresh token from an encrypted box
final http.Response response =
await http.post(Uri.parse('http://example.com/refresh'),
headers: <String, String>{'Content-Type': 'application/json; charset=UTF-8'},
body: jsonEncode(<String?, dynamic>{
'email': currentemail,
'id': currentuserid,
'refreshToken': refreshToken
}),
);
if (response.body.contains('token')) {
Map<String, dynamic> refreshMap = json.decode(response.body);
String token = refreshMap['token'];
putCryptJWT(token); // stores new token in encrypted Hive box
print("token renewed = " + token);
Timer(Duration(minutes: 55), () {
refreshToken();
});
return token;
} else {
String noresponse = 'responsebody doesnt contain token';
print(noresponse);
}
}
安卓工作室首先在refreshToken()
下给了我一个带红线的null错误,并建议对!
进行null检查。但一旦我这样做了,我就犯了这个错误;
The expression doesn't evaluate to a function, so it can't be invoked.
它建议我删除getter调用中的括号。所以我去掉了括号和空校验,只剩下refreshToken
;
但它并不像我希望的那样每55分钟运行一次。
我宁愿不在每次查询时都检查过期日期。我的JWTToken及其RefreshToken都存储在加密的配置单元框中。因此,检查每个查询似乎有点过于密集。
我不建议这样做。你正在为自己创造很多工作。更好的方法是拦截您请求的响应。检查响应代码是否为401(意味着未经授权(,我想这就是你的后端会返回的代码。然后刷新令牌,并再次激发原始请求。这是一种更加无缝的工作方式,因此没有不必要的令牌过期检查,用户体验仍然无缝。你可以很容易地做到这与迪奥,包。你可以这样做。
var _http;
void initMethod(){
_http = Dio();
//set some headers
_http.options.contentType = "application/json";
_http.options.headers['Content-Type'] = "application/json";
//Now add interceptors for both request and response to add a token on outgoing request and to handle refresh on failed response.
_http.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
return await _addAuthenticationToken(options);
}, onResponse: (Response response) async {
if (response.statusCode == 401) return await refreshToken(response);
return response;
}));
}
Future<Response> refreshtoken(Response response){
//Get your new token here
//Once you have the token, retry the original failed request. (After you set the token where ever you store it etc)
return await _retry(response);
}
Future<RequestOptions> _addAuthenticationToken(RequestOptions options) async {
if (tokenPair != null)
options.headers['Authorization'] =
"Bearer " + "yout token goes here";
return options;
}
Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {
final options = new Options(
method: requestOptions.method,
headers: requestOptions.headers,
);
return await this._http.request<dynamic>(requestOptions.path,
data: requestOptions.data,
queryParameters: requestOptions.queryParameters,
options: options);
}
你可能需要进行实验来检查你是否得到了想要的结果,但这应该能达到的效果
在某些情况下,您无法从后端获得响应,这就是我的情况。自从我开始获取代币以来,我在应用程序中添加了计数器,并不断计数。你的方法是回复我之前测试过的CPU时钟,它不精确,有些设备可能计数更快,有些甚至更慢。我的方法是现在使用日期时间,现在用我们在开始时每15秒保存一次的时间戳来检查不同的日期时间,所以它仍然不完全准确,但至少错误不应该超过15秒
DateTime _timeoutAt;
start() {
_timeoutAt = DateTime.now().add(Duration(minutes: 55);
Timer _timerCheckIsTimeout = Timer.periodic(Duration(seconds: 15), (timer) {
final isTimeout = DateTime.now().isAfter(_timeoutAt)
if (isTimeout) {
//Call back from here
await refreshToken();
timer.cancel();
}
}
我知道这不是最好的做法,但人们有不同的条件,他们无法拿出最好的做法。如果您可以控制后端对其进行响应,请使用上面的示例。
我不知道这是否比使用Dio更可取,但我只是对所有HTTP发布请求都这样做;
else if (response.body.contains('TokenExpiredError')) {
await refreshToken();
return downloadMainJSON(
);
它似乎运行良好。