flutter firebase 使用 refreshToken 自动刷新用户会话 [英] flutter firebase auto refresh user session with refreshToken

查看:44
本文介绍了flutter firebase 使用 refreshToken 自动刷新用户会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望我的应用程序中的用户保持登录状态.我正在使用带有 IDToken 的 Firebase 身份验证,该身份验证持续 1 小时,直到它过期.如果会话即将过期,我想每次都自动刷新会话.

I want user in my app to stay logged in. I'm using the firebase authentification with IDToken which lasts for 1hour until it expires. I want to auto refresh the session everytime if it is going to expire.

到目前为止我在这里读到的内容https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token 使用 https://securetoken.googleapis.com/v1/token?key=[API_KEY]

what Ive read so far here https://firebase.google.com/docs/reference/rest/auth/#section-refresh-token it should be somehow possible with https://securetoken.googleapis.com/v1/token?key=[API_KEY]

这是我现在用于身份验证的完整代码(flutter)

This is my full code for authentification right now (flutter)

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../provider/http_exception.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';

class Auth with ChangeNotifier {
  String _token;
  DateTime _expiryDate;
  String _userId;
  Timer _authTimer;
  bool wasLoggedOut = false;
  bool onBoarding = false;

  Future<void> createUser(String email, String firstName, String lastName) async {
    final url = 'https://test45.firebaseio.com/users/$userId.json?auth=$token';
    final response = await http.put(url, body: json.encode({
      'userEmail': email,
      'userIsArtist': false,
      'userFirstName': firstName,
      'userLastName': lastName,
    }));
    print('post ist done');
    print(json.decode(response.body));
  }

  bool get isAuth {
    return token != null;
  }

  String get userId {
    return _userId;
  }

  String get token {
    if (_expiryDate != null &&
        _expiryDate.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    return null;
  }

  Future<void> authenticate(
      String email, String password, String urlSegement) async {
    final url = 'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegement?key=AIzaSyD8pb3M325252dfsDC-4535dfd';

    try {
      final response = await http.post(url,
          body: json.encode({
            'email': email,
            'password': password,
            'returnSecureToken': true,
          }));
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      }
      _token = responseData['idToken'];
      _userId = responseData['localId'];
      _expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expiresIn'])));
      _autoLogout();
     
      notifyListeners();

      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode({
        'token': _token,
        'userId': _userId,
        'expiryDate': _expiryDate.toIso8601String(),
      });
      prefs.setString('userData', userData);
    } catch (error) {
      throw error;
    }
  }

  Future<void> signup(String email, String password) async {
    return authenticate(email, password, 'signUp');
  }

  Future<void> signin(String email, String password) async {
    return authenticate(email, password, 'signInWithPassword');
  }

  Future<bool> tryAutoLogin() async {
    final prefs = await SharedPreferences.getInstance();
    if(!prefs.containsKey('userData')){
      return false;
    }
    final extractedUserData = json.decode(prefs.getString('userData')) as Map<String, Object>;
    final expiryDate = DateTime.parse(extractedUserData['expiryDate']);

    if(expiryDate.isBefore(DateTime.now())) {
      return false;
    }

    _token = extractedUserData['token'];
    _userId = extractedUserData['userId'];
    _expiryDate = expiryDate;

    notifyListeners();
    _autoLogout();
    return true;
  }


  Future<void> logout() async {
    _token = null;
    _userId = null;
    _expiryDate = null;
    if(_authTimer != null){
      _authTimer.cancel();
      _authTimer = null;
    }
    notifyListeners();
    final prefs = await SharedPreferences.getInstance();
    prefs.remove('userData');
  }

  void _autoLogout() {
    if(_authTimer != null) {
      _authTimer.cancel();
    }
  final timetoExpiry =  _expiryDate.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timetoExpiry), logout);
  }
}

如何修改我的auth.dart来实现自动刷新?

how to modify my auth.dart to achieve the auto refreshing?

正如评论中提到的,我与提供者合作,我有以下功能来检索令牌:

As mentioned in the comments, im working with providers where I have the following functions to retrieve the token:

update(String token, id, List<items> itemsList) {
    authToken = token;
    userId = id;
  }

也在我的每个 API 调用中使用 auth 参数:

also in every of my API calls im using the auth parameter already:

var url = 'https://test45.firebaseio.com/folder/$inside/$ym.json?auth=$authToken';

我只需要一个可以向我展示如何使用刷新令牌修改我的代码的人.

I just need somebody who can show me how to modify my code with the refresh token.

提前致谢!

我试图实现它,但我遇到了无限循环,请帮忙:

I tried to implement it, but im getting an infinite loop, please help:

String get token {
    if (_expiryDate != null &&
        _expiryDate.isAfter(DateTime.now()) &&
        _token != null) {
      return _token;
    }
    refreshSession();
  }

  Future<void> refreshSession() async {
        final url = 'https://securetoken.googleapis.com/v1/token?key=5437fdjskfsdk38438?grant_type=refresh_token?auth=$token';
      
      try {
      final response = await http.post(url,
          body: json.encode({
  'token_type': 'Bearer',
          }));
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      }
      _token = responseData['id_token'];
      _userId = responseData['user_id'];
      _expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expires_in'])));
      _autoLogout();
     
      notifyListeners();

      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode({
        'token': _token,
        'userId': _userId,
        'expiryDate': _expiryDate.toIso8601String(),
      });
      prefs.setString('userData', userData);
    } catch (error) {
      throw error;
    }
      }

推荐答案

我编辑了你的 refresh_token() 函数.

I edited your refresh_token() function.

首先,您应该在带有链接的 firebase 项目中使用您的 web api 密钥.您还应该保存刷新令牌.如果你像这样发布,它会起作用.如果不起作用,请尝试在我提交时在您的身体上不使用 json.encode() 函数.

Firstly, you should use your web api key on your firebase project with the link. You should also save the refresh token. And if you post like this, it will work. If don't work, try without json.encode() function on your body as I commit.

Future<void> refreshSession() async {
  final url =
      'https://securetoken.googleapis.com/v1/token?key=$WEB_API_KEY'; 
  //$WEB_API_KEY=> You should write your web api key on your firebase project.
  
  try {
    final response = await http.post(
      url,
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: json.encode({
        'grant_type': 'refresh_token',
        'refresh_token': '[REFRESH_TOKEN]', // Your refresh token.
      }),
      // Or try without json.encode.
      // Like this:
      // body: {
      //   'grant_type': 'refresh_token',
      //   'refresh_token': '[REFRESH_TOKEN]',
      // },
    );
    final responseData = json.decode(response.body);
    if (responseData['error'] != null) {
      throw HttpException(responseData['error']['message']);
    }
    _token = responseData['id_token'];
    _refresh_token = responseData['refresh_token']; // Also save your refresh token
    _userId = responseData['user_id'];
    _expiryDate = DateTime.now()
        .add(Duration(seconds: int.parse(responseData['expires_in'])));
    _autoLogout();

    notifyListeners();

    final prefs = await SharedPreferences.getInstance();
    final userData = json.encode({
      'token': _token,
      'refresh_token': _refresh_token,
      'userId': _userId,
      'expiryDate': _expiryDate.toIso8601String(),
    });
    prefs.setString('userData', userData);
  } catch (error) {
    throw error;
  }
}


这是我编辑过的完整 auth.dart 文件.


This is your full auth.dart file which I edited.

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../provider/http_exception.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';

class Auth with ChangeNotifier {
  String _token;
  String _refresh_token;
  DateTime _expiryDate;
  String _userId;
  Timer _authTimer;
  bool wasLoggedOut = false;
  bool onBoarding = false;

  Future<void> createUser(String email, String firstName, String lastName) async {
    final url = 'https://test45.firebaseio.com/users/$userId.json?auth=$token';
    final response = await http.put(url, body: json.encode({
      'userEmail': email,
      'userIsArtist': false,
      'userFirstName': firstName,
      'userLastName': lastName,
    }));
    print('post ist done');
    print(json.decode(response.body));
  }

  bool get isAuth {
    return token != null;
  }

  String get userId {
    return _userId;
  }

  String get token {
    if (_expiryDate != null &&
        _expiryDate.isAfter(DateTime.now()) &&
        _token != null && _refresh_token!=null) {
      return _token;
    }
    refreshSession();
    return null;
  }

  Future<void> authenticate(
      String email, String password, String urlSegement) async {
    final url = 'https://identitytoolkit.googleapis.com/v1/accounts:$urlSegement?key=AIzaSyD8pb3M325252dfsDC-4535dfd';

    try {
      final response = await http.post(url,
          body: json.encode({
            'email': email,
            'password': password,
            'returnSecureToken': true,
          }));
      final responseData = json.decode(response.body);
      if (responseData['error'] != null) {
        throw HttpException(responseData['error']['message']);
      }
      _token = responseData['idToken'];
      _refresh_token = responseData['refreshToken'];
      _userId = responseData['localId'];
      _expiryDate = DateTime.now().add(Duration(seconds: int.parse(responseData['expiresIn'])));
      _autoLogout();
     
      notifyListeners();

      final prefs = await SharedPreferences.getInstance();
      final userData = json.encode({
        'token': _token,
        'refresh_token': _refresh_token,
        'userId': _userId,
        'expiryDate': _expiryDate.toIso8601String(),
      });
      prefs.setString('userData', userData);
    } catch (error) {
      throw error;
    }
  }

  Future<void> signup(String email, String password) async {
    return authenticate(email, password, 'signUp');
  }

  Future<void> signin(String email, String password) async {
    return authenticate(email, password, 'signInWithPassword');
  }

  Future<bool> tryAutoLogin() async {
    final prefs = await SharedPreferences.getInstance();
    if(!prefs.containsKey('userData')){
      return false;
    }
    final extractedUserData = json.decode(prefs.getString('userData')) as Map<String, Object>;
    final expiryDate = DateTime.parse(extractedUserData['expiryDate']);

    if(expiryDate.isBefore(DateTime.now())) {
      return false;
    }

    _token = extractedUserData['token'];
    _refresh_token = extractedUserData['refresh_token'];
    _userId = extractedUserData['userId'];
    _expiryDate = expiryDate;

    notifyListeners();
    _autoLogout();
    return true;
  }


  Future<void> logout() async {
    _token = null;
    _refresh_token = null;
    _userId = null;
    _expiryDate = null;
    if(_authTimer != null){
      _authTimer.cancel();
      _authTimer = null;
    }
    notifyListeners();
    final prefs = await SharedPreferences.getInstance();
    prefs.remove('userData');
  }

  void _autoLogout() {
    if(_authTimer != null) {
      _authTimer.cancel();
    }
  final timetoExpiry =  _expiryDate.difference(DateTime.now()).inSeconds;
    _authTimer = Timer(Duration(seconds: timetoExpiry), logout);
  }
  
  


Future<void> refreshSession() async {
  final url =
      'https://securetoken.googleapis.com/v1/token?key=$WEB_API_KEY'; 
  //$WEB_API_KEY=> You should write your web api key on your firebase project.
  
  try {
    final response = await http.post(
      url,
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: json.encode({
        'grant_type': 'refresh_token',
        'refresh_token': '[REFRESH_TOKEN]', // Your refresh token.
      }),
      // Or try without json.encode.
      // Like this:
      // body: {
      //   'grant_type': 'refresh_token',
      //   'refresh_token': '[REFRESH_TOKEN]',
      // },
    );
    final responseData = json.decode(response.body);
    if (responseData['error'] != null) {
      throw HttpException(responseData['error']['message']);
    }
    _token = responseData['id_token'];
    _refresh_token = responseData['refresh_token']; // Also save your refresh token
    _userId = responseData['user_id'];
    _expiryDate = DateTime.now()
        .add(Duration(seconds: int.parse(responseData['expires_in'])));
    _autoLogout();

    notifyListeners();

    final prefs = await SharedPreferences.getInstance();
    final userData = json.encode({
      'token': _token,
      'refresh_token': _refresh_token,
      'userId': _userId,
      'expiryDate': _expiryDate.toIso8601String(),
    });
    prefs.setString('userData', userData);
  } catch (error) {
    throw error;
  }
}
}

这篇关于flutter firebase 使用 refreshToken 自动刷新用户会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆