How to dynamically save token after logging to shared prefernces - flutter

How to dynamically auth users and save tokens in shared pref?
I understood how to save token in sharedprefernces, but can't understand how to take it dynamically by login/password and pass token from it to sharedpref dynamically in loginWithToken(); beacuse I use this function for auth in
final httpConnectionOptions = HttpConnectionOptions(
accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
and it is required only String
My code now is like that:
Here is request where I am making request to get token:
Future<String?> getToken(String password, String login) async {
String _email = "admin";
String _password = "123";
Map<String, String> headers = {
'Content-Type': 'application/json',
'accept': ' */*'
};
final body = {
'username': _email,
'password': _password,
};
var response = await http.post(
Uri.parse("http://mylink/login"),
headers: headers,
body: jsonEncode(body),
);
if (response.statusCode == 200) {
var value = jsonEncode(response.body);
return value;
}
return null;
}
here is I created logging logic:
final TextEditingController _loginController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
ElevatedButton(
onPressed: () async {
var username = _loginController.text;
var password = _passwordController.text;
var jwt = await ProviderService()
.getToken(password, username);
if (jwt != null) {
SharedPreferenceService().setToken(jwt);
Navigator.pushNamed(
context, '/mainPageAdmin');
} else {
displayDialog(context);
}
},
here is my shared pref. I can't understand how to put new token value in that string, after paaword and login was sent.
String tokens = 'dhjwhdwdwkjdhdkje';
Future<bool> getSharedPreferencesInstance() async {
_prefs = await SharedPreferences.getInstance().catchError((e) {
print("shared preferences error : $e");
return false;
});
return true;
}
Future setToken(String token) async {
await _prefs?.setString('token', token);
}
Future clearToken() async {
await _prefs?.clear();
}
Future<String> get token async => _prefs?.getString('token') ?? '';
Future<String> loginWithToken() async {
bool value = await getSharedPreferencesInstance();
if (value == true) {
setToken("Bearer $tokens");
// print(tokens);
}
return tokens;
}
Api Responce:
{
"$id": "1",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZ",
"user": {
"$id": "2"
}
}
Auth class I parsed:
Auth authFromJson(String str) => Auth.fromJson(json.decode(str));
String authToJson(Auth data) => json.encode(data.toJson());
class Auth {
Auth({
this.token,
this.user,
});
final String? token;
final User? user;
factory Auth.fromJson(Map<String, dynamic> json) => Auth(
token: json["token"],
user: User.fromJson(json["user"]),
);
Map<String, dynamic> toJson() => {
"token": token,
"user": user!.toJson(),
};
}

In your getToken function do this:
if (response.statusCode == 200) {
var value = jsonEncode(response.body) as Map<String, dynamic>;
await setToken(value['token']);
return value;
}

Related

how to resend multipart request

I am retrying my api call if get 401 response but when Retrying I am ending with an following exception
following is my code for retrying multipart I had used http_interceptor package for retrying Api Calls
interceptor.dart
class AuthorizationInterceptor extends InterceptorContract {
#override
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
final prefs = await SharedPreferences.getInstance();
final extractData =
json.decode(prefs.getString('userData')!) as Map<String, dynamic>;
final Map<String, String> headers = Map.from(request.headers);
headers['Authorization'] = await extractData['accessToken'];
print(
'this is from AuthorizationInterceptor: ${extractData['accessToken']}');
// TODO: implement interceptRequest
return request.copyWith(
headers: headers,
);
}
retry.dart
class ExpiredTokenRetryPolicy extends RetryPolicy {
BuildContext context;
ExpiredTokenRetryPolicy(this.context);
#override
// TODO: implement maxRetryAttempts
int get maxRetryAttempts => 2;
#override
Future<bool> shouldAttemptRetryOnResponse(BaseResponse response) async {
if (response.statusCode == 401) {
print('retry token started');
//perform token refresh,get the new token and update it in the secure storage
await Provider.of<Auth>(context, listen: false).restoreAccessToken();
return true;
}
return false;
}
I am using interceptors in my widget following is my code where I am using interceptors and using retry policy
#override
Widget build(BuildContext context) {
var flutterFunctions = Provider.of<FlutterFunctions>(context);
// print('this is from insert package${token.token}');
ApiCalls repository = ApiCalls(
client: InterceptedClient.build(
retryPolicy: ExpiredTokenRetryPolicy(context),
interceptors: [
AuthorizationInterceptor(),
],
),
);
following is my restore access token method
Future<void> restoreAccessToken() async {
print('restoreAccessToken started');
//print(token);
final url = '${Ninecabsapi().urlHost}${Ninecabsapi().login}/$sessionId';
var response = await http.patch(
Uri.parse(url),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': accessToken!
},
body: json.encode(
{"refresh_token": refreshtoken},
),
);
var userDetails = json.decode(response.body);
if (response.statusCode == 401) {
print(userDetails['messages']);
}
sessionId = userDetails['data']['session_id'];
accessToken = userDetails['data']['access_token'];
accessTokenExpiryDate = DateTime.now().add(
Duration(seconds: userDetails['data']['access_token_expiry']),
);
refreshToken = userDetails['data']['refresh_token'];
refreshTokenExpiryDate = DateTime.now().add(
Duration(seconds: userDetails['data']['refresh_token_expiry']),
);
final userData = json.encode({
'sessionId': sessionId,
'refreshToken': refreshToken,
'refreshExpiry': refreshTokenExpiryDate!.toIso8601String(),
'accessToken': accessToken,
'accessTokenExpiry': accessTokenExpiryDate!.toIso8601String()
});
//print(userDetails);
notifyListeners();
final prefs = await SharedPreferences.getInstance();
prefs.setString('userData', userData);
print("this is from restoreAcessToken :$userDetails");
final extractData =
json.decode(prefs.getString('userData')!) as Map<String, dynamic>;
print('restore access token: ${extractData['accessToken']}');
reset();
}
As a rule. You must NOT write using the same Stream/MultipartFile more than once. If you need to retry sending to the same destination, you have to use a new MultipartFile each time you retry.

An optimize way for tryAutoLogin function in flutter?

I want to create a function for auto login like Facebook in flutter but don't know the best way to do it.
My function for login and auto login, I used SharedPreferences plugin for store data.
SignIn function:
Future<void> signIn(String userName, String pass) async {
final url = Uri.parse('MyAPI_login');// sorry it for privacy
debugPrint("$userName / $pass");
try {
var respone = await http.post(url, body: {
'user_name': userName,
'password': pass,
'platform': 'mobile',
'device_token': '',
});
final reponseData = jsonDecode(respone.body);
_userName = userName;
_token = reponseData['data']['accessToken'];
_expiryDate = DateTime.now().add(Duration(
seconds: int.parse(reponseData['data']['tokenExpireAt'].toString())));
_refreshToken = reponseData['data']['refreshToken'].toString();
_timerRefreshToken =
int.parse(reponseData['data']['refreshTokenExpireAt'].toString());
// debugPrint(
// '$_token \n $_expiryDate \n $_refreshToken \n $_timerRefreshToken');
notifyListeners();
final prefs = await SharedPreferences.getInstance();
final userData = json.encode({
'_userId': _userName.toString(),
'token': _token.toString(),
'expiryDate': _expiryDate!.toIso8601String(),
'refreshToken': _refreshToken,
'timerRefreshToken': _timerRefreshToken.toString(),
});
await prefs.setString('userData', userData);
} catch (error) {
throw Exception(error.toString());
}}
TryAutoLogin function:
Future<bool> tryAutoLogin() async {
final prefs = await SharedPreferences.getInstance();
if (!prefs.containsKey('userData')) {
return false;
}
final extractedUserData = json
.decode(prefs.getString('userData').toString()) as Map<String, dynamic>;
final expiryDate =
DateTime.parse(extractedUserData['expiryDate'].toString());
if (expiryDate.isBefore(DateTime.now())) {
_token = extractedUserData['refreshToken'].toString();
_expiryDate = DateTime.now().add(
Duration(seconds: int.parse(extractedUserData['timerRefreshToken'])));
_refreshNewToken(extractedUserData['refreshToken'].toString());
}
return true;}
RefreshNewToken function:
Future<void> _refreshNewToken(String oldRefreshToken) async {
final url =
Uri.parse('MyAPI_refreshtoken');
var respone = await http.post(url, body: {'refreshToken': oldRefreshToken});
debugPrint(respone.body);}
My API for login response is like this:
{"data":{"tokenKey":"Authorization","tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1YzkyMTQwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTMsImV4cCI6MTY1ODI4NTk5M30.3kMByfweUhzQM-4d5S0G7tUaC0e-nZLJF3_dbdV_7fM","tokenExpireAt":1658285940964,"refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1YzkyMTQwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTMsImV4cCI6MTY1ODM2ODc5M30.Bv7PZrnx9zDzwIuxNMppFxlwZlJEnthVjEYBKYl-aWM","refreshTokenExpireAt":1658368740964},"message":"Logged in successfully!","status":200,"errors":null}
Also, my API has a refresh token request, it returns like this:
{"data":{"tokenKey":"Authorization","tokenType":"Bearer","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1ZjQyOGUwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTQsImV4cCI6MTY1ODI4NTk5NH0.wcyouoprMHFnRD4_oSpP9RSasxMBrktX6nZI2x2PQec","tokenExpireAt":1658285940242,"refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl9pZCI6ImE1ZjQyOGUwLTA3Y2YtMTFlZC1hNDQ2LTYzY2YyNjNiZjllMiIsInVzZXJfaWQiOiJDODAzQ0I3RS1CQTcyLTQ4NjgtQjdEMC05NkRBOUNCREQyMTkiLCJ1c2VyX25hbWUiOiIxMDAyMCIsImZ1bGxfbmFtZSI6IkzDqiBUaOG7iyBMacOqbiIsImlzQWRtaW5pc3RyYXRvciI6MCwidXNlcl9jb21wYW5pZXMiOltdLCJpYXQiOjE2NTgyODIzOTQsImV4cCI6MTY1ODM2ODc5NH0.y-8MP4M_1LzCwmqo_KQZGyQXkycrxdOLWz_fdqIPRyQ","refreshTokenExpireAt":1658368740242},"message":"Request successfully!","status":200,"errors":null}

Get token auth value to another dart using sharedprefence

how to retrieve token variable from sharedprefence in flutter?
i am very new to implement api for my flutter project because previously I was only told to work on the frontend, i have saved auth token in login and here is my code to store token in sharedprefence
signIn(String email, password) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email': email,
'password': password
};
var jsonResponse = null;
var response = await http.post(Uri.parse("/api/login"), body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if(jsonResponse != null) {
setState(() {
_isLoading = false;
});
sharedPreferences.setString("token", jsonResponse['data']['token']['original']['token']);
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => HomePage()), (Route<dynamic> route) => false);
}
}
else {
setState(() {
_isLoading = false;
});
scaffoldMessenger.showSnackBar(SnackBar(content:Text("Mohon cek Email dan Password kembali!", textAlign: TextAlign.center,), backgroundColor: Colors.red,));
}
}
and here is the darts place that I want to call the token for auth in the post method
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:kiriapp/models/angkot.dart';
class AngkotProvider with ChangeNotifier {
late AngkotModel _angkot;
AngkotModel get angkot => _angkot;
set angkot(AngkotModel newAngkot) {
_angkot = newAngkot;
notifyListeners();
}
static Future<AngkotModel?> tambah(
String user_id,
String route_id,
String plat_nomor,
String pajak_tahunan,
String pajak_stnk,
String kir_bulanan) async {
try {
var body = {
'user_id': user_id,
'route_id': route_id,
'plat_nomor': plat_nomor,
'pajak_tahunan': pajak_tahunan,
'pajak_stnk': pajak_stnk,
'kir_bulanan': kir_bulanan,
};
print(body);
var response = await http.post(
Uri.parse('api/create'),
headers: {
'Authorization': 'Bearer $howtocallthetoken?,
},
body: body,
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 201) {
return AngkotModel.fromJson(jsonDecode(response.body));
} else if (response.statusCode == 400) {
return AngkotModel.fromJson(jsonDecode(response.body));
}{
return null;
}
} catch (e) {
print(e);
return null;
}
}
}
thanks
To store something in shared preference we use setString function, just like you did. Now to retrieve it, you should use getString and it will return the token you stored earlier.
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
String accessToken = sharedPreferences.getString("token");
var response = await http.post(
Uri.parse('api/create'),
headers: {
'Authorization': 'Bearer $accessToken',
},
body: body,
);
Don't forget to make the function async, and handle null values as the getString function might return token as null if not stored correctly.

how to set values in initState method using riverpod

right now i have a ChangeNotifierProvider, and i want to set some values straight in the initState method.
those values come from a backend API, that are retrieved in that provider.
I am stuck is this situation for a while now, hope i can get some help.
Here is the ChangeNotifierProvider
final userProvider = ChangeNotifierProvider.autoDispose.family<UserProxy, String>((ref, id) {
var notifier = UserProxy(userId: id);
notifier.load();
return notifier;
});
class UserProxy extends ChangeNotifier {
String userId;
User? user;
UserProxy({this.userId = ""});
void load() async {
await getUser().then((value) => generateObject(value));
}
Future<String> getUser() async {
Map<String, String> queryParams = {
"id": userId,
};
var url = Uri.https("asdadas.asdasd.com", "endpoint", queryParams);
Map<String, String> headers = {
'content-type': "application/json",
};
var response = await http.get(url,
headers: headers,);
print(response.body);
return response.body;
}
User generateObject(String jsonString) {
this.user = User.fromJson(jsonDecode(jsonString));
notifyListeners();
return this.user ?? User();
}
}
For this case I would suggest
FutureProvider.autoDispose.family<UserProxy, String>((ref, id) async { .... })
then change your StateWidget to ConsumerStatefulWidget and ConsumerState<>
then
ref.watch(provider(11)).when(
loading: (){},
error: (Object err, StackTrace? st){ },
data: (user){
// build widget with result here.
},
)

I Want to get the token from my API by Dio flutter?

I'm trying to get my token from the API but it's empty
This is dio functions
import 'package:dio/dio.dart';
class DioHelper
{
static Dio dio;
static init()
{
print('dioHelper Initialized');
dio = Dio(
BaseOptions(
baseUrl:'my api link',
receiveDataWhenStatusError: true,
));
}
static Future<Response> getData ({
String url,
Map<String,dynamic> query,
String lang = 'en',
String token,
Map<String,dynamic> data,
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.get(
url,
queryParameters: query
);
}
static Future<Response> postData ({
String url,
Map<String,dynamic> query,
Map<String,dynamic> data,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.post(
url,
queryParameters: query,
data: data,
);
}
static Future<Response> putData ({
String url,
Map<String,dynamic> query,
Map<String,dynamic> data,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.put(
url,
queryParameters: query,
data: data,
);
}
static Future<Response> deleteData ({
String url,
String lang = 'ar',
String token
})async
{
dio.options.headers =
{
'lang':'$lang',
'Content-Type':'application/json',
'Authorization' : '$token'
};
return await dio.delete(url);
}
}
and pass value in this variable
String token = '';
and fuctions sharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
class CacheHelper
{
static SharedPreferences sharedPreferences;
static init () async {
sharedPreferences = await SharedPreferences.getInstance();
}
static dynamic getData(String key, ){
return sharedPreferences.get(key);
}
static Future<bool> saveData({ String key, dynamic value})async{
if(value is String) return await sharedPreferences.setString(key, value);
if(value is int) return await sharedPreferences.setInt(key, value);
if(value is bool) return await sharedPreferences.setBool(key, value);
return await sharedPreferences.setDouble(key, value);
}
static Future<bool> removeData (String key)async{
return await sharedPreferences.remove(key);
}
}
*CALL THE TOKEN*
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
Bloc.observer = MyBlocObserver();
await DioHelper.init();
await CacheHelper.init();
token = CacheHelper.getData('token');
var IsLogin = CacheHelper.getData( 'IsLogin');
var IsBoarding = CacheHelper.getData( 'IsBoarding');
print(IsLogin);
print(IsBoarding);
print(token);
var widget;
if (IsBoarding != null) {
if (token == null) {
widget = ShopingScreen();
} else {
widget = Login_Screen();
}
} else {
widget = BordScreen();
}
THANKS
Is there any solution
I described my problem a few days ago, but without details, there was no useful solution
Tried a lot but it didn't solve this problem. I tried wiping the phone data or reformatting the codes and restarting the device several times.