Error while logging in (on the server) in the flutter application - flutter

I have an application that has a piece of code that is responsible for authorization. I sent the encrypted data to the server, the data on the server will be checked, if everything is fine with the data, then I return the code 200 and additional data. I tested this code on the server without protection (http). But now when I started debugging this application with a server that has a certificate (https) I had a problem. Maybe someone knows how to solve this problem? Here is the problem code:
E/flutter (23247): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: HandshakeException: Handshake error in client (OS Error:
E/flutter (23247): CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:354))
Here is my code:
signIn(String login, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var AESLogin = login;
var AESpass = pass;
//generate a 16-byte random key
var key = '33CC2E0DD531B761316FE1231231211';
print(key);
//encrypt
var encryptLogin = await FlutterAesEcbPkcs5.encryptString(AESLogin, key);
var encryptPass = await FlutterAesEcbPkcs5.encryptString(AESpass, key);
var jsonResponse = null;
var response = await http.post(
global.urlVar + "/auth_user", body: json.encode(
{
"login": encryptLogin,
"pass": encryptPass
}),
);
if (response.statusCode == 200) {
jsonResponse = json.decode(response.body);
print('Response body: ${response.body}');
if (jsonResponse['message'] ==
'200') { //if( jsonResponse['message'] == '200') {
setState(() {
_isLoading = false;
});
global.nameUser = jsonResponse['name'];
global.dataArea = jsonResponse['data_area'];
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}
else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Error_Auth()),
);
}
}
else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}

Related

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 handle "Lost connection to device." error

I created an app, which contains login and dashboard screen, i used Nodejs backend and mongodb also. i trying to add functionality when user logged in and close the app without logging out and then when user come to the app it should display where it left last time. so i used shared preference for it. I am testing it now, when i logged in and close the app using the right-most button (which shows all the currently running apps) it send me this "Lost connection to device.
".
login Code:
bool newuser;
String type ;
SharedPreferences myPrefs;
void initState() {
checkIfLoggedinalready();
}
Future login() async {
try {
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
} catch (e) {
}
}
void checkIfLoggedinalready() async{
myPrefs = await SharedPreferences.getInstance();
newuser = (myPrefs.getBool('login') ?? true);
print(newuser);
if (newuser == false && type == 'Employee') {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Employee()));
}
}
dashboard code:
i am doing this on drawer code where i use logout
new ListTile(
title: new Text('Log out'),
leading: Icon(Icons.logout,color:Colors.grey),
onTap: (){
myPrefs.setBool('login', true); //here i set it to true, if user is new
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>
Login()
)
);
},
),
please help it would be appreciated.
Lost connection to device is not a coding issue, your linked device got disconnected at that time due to data cable, If you will test this on emulator then you will not get this issue.
If you are saving user data on Shared preference then do encode your sensitive data before saving it.
var response =
await http.post(Uri.parse(parseUse), body: json.encode(data), headers: { "Content-Type": "application/json; charset=UTF-8", }).timeout(Duration(minutes: 2));
Updated Answer :
try{
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
}on DioError catch (e){
if(e.type == DioErrorType.connectTimeout){
"You can put a alert dialog or something you prefer".
}
}
or you can also use base Option since your using DIO
var dio = Dio(); // with default Options
// Set default configs
dio.options.baseUrl = 'https://www.xx.com/api';
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout = 3000;
// or new Dio with a BaseOptions instance.
var options = BaseOptions(
baseUrl: 'https://www.xx.com/api',
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = Dio(options);
response = await dio.request(
'/test',
data: {'id':12,'name':'xx'},
options: Options(method:'GET'),
);

Passing token in Flutter from auth to http-request

how to pass the token value from above code to another screen into a http-request as variable.
class AppStarted extends AuthenticationEvent {}
class LoggedIn extends AuthenticationEvent {
final String token;
const LoggedIn({#required this.token});
#override
List<Object> get props => [token];
#override
String toString() => 'LoggedIn { token: $token }';
}
Thank you for your help, haning on this for 2 hours now...
first create a class where your where https request handle & token store
class Network {
var token;
final string base= "/api";
//token get when needed
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var user = jsonDecode(localStorage.getString('data'));
token = user['token'];
}
//signup
signUp(data, apiUrl) async {
var fullUrl = baseUrl + apiUrl;
return await http.post(fullUrl,
body: jsonEncode(data), headers: _setHeaders());
}
//login
signIn(apiUrl) async {
var fullUrl = baseUrl + apiUrl;
await _getToken();
return await http.get(fullUrl, headers: _setHeaders());
}
}
in sign up page use this method where you use sign up button on pressed
void _signUp() async {
var data = {
'mobile': mobileController.text,
'password': mobileController.text,
};
var res = await Network().signUp(data, '/register');
var body = json.decode(res.body);
if (body.statusCode == 200) {
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('token', json.encode(body['data']['token']));
localStorage.setString('data', json.encode(body['data']));
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => Home()),
);
} else {
// errorMessage = "as you want to show ";
}
}
in sign up page , use this method same as sign up pages
void signIn() async {
var data = {'mobile': mobile, 'password': password};
var res = await Network().signIn(data, '/login');
var body = json.decode(res.body);
if (res.statusCode == 200) {
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('token', json.encode(body['data']['token']));
localStorage.setString('data', json.encode(body['data']));
Navigator.pushReplacement(
context,
new MaterialPageRoute(builder: (context) => HomePage()),
);
} else if (res.statusCode != 200) {
// mobileError = "These credentials do not match our records.";
}
}
now you can have the token when u signup/singIn and store token in sharedSharedPreferences
whenever you try to acces token just called _getToken() method

How to show error if server is unreachable flutter

Am still pretty new to flutter. I have a network call to be executed. But before doing that I need to check whether the device have internet connectivity and that the server is api server is reachable. I have managed to check if the internet connectivity is available, but cant show an when server is not reachable
This is what i have done so far:
login(username, password) async {
final String url = "http://10.0.2.2:8080/api/auth/signin"; // iOS
var responseJson;
try {
final response= await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'username': username,
'password': password,
}),
);
responseJson = _response(response);
} on SocketException {
throw FetchDataException('No Internet connection');
}
print(responseJson);
SharedPreferences prefs = await SharedPreferences.getInstance();
var parse = jsonDecode(responseJson.body);
await prefs.setString('username', parse["username"]);
await prefs.setString('message', parse["message"]);
await prefs.setString('accessToken', parse["accessToken"]);
return responseJson;
}
dynamic _response(http.Response response) {
switch (response.statusCode) {
case 200:
var responseJson = json.decode(response.body.toString());
print(responseJson);
return responseJson;
case 400:
throw BadRequestException(response.body.toString());
case 401:
case 403:
throw UnauthorisedException(response.body.toString());
case 500:
throw FetchDataException(
'Error occured while Communication with Server with StatusCode : ${response
.statusCode}');
default:
throw FetchDataException(
'Error occured while Communication with Server with StatusCode : ${response
.statusCode}');
}
}
My login button function
RoundedButton(
text: "LOGIN",
press: () async {
if (_formKey.currentState.validate()) {
progressDialog.show();
await login(
username,
password,
);
SharedPreferences prefs =
await SharedPreferences.getInstance();
String token = prefs.getString("accessToken");
print(token);
if (token == null) {
progressDialog.hide();
showAlertsDialog(context);
} else {
showAlertzDialog(context);
}
}
},
)
Whenever I switch of the server and click on login, the app is stuck a progress bar showing signing in. How can I display an alert that there is no connection to the server?
This is how you can manage your API call.
Future<dynamic> requestGET({String url}) async {
try {
final response = await http.get(Uri.parse(url));
switch (response.statusCode) {
case 200:
case 201:
final result = jsonDecode(response.body);
final jsonResponse = {'success': true, 'response': result};
return jsonResponse;
case 400:
final result = jsonDecode(response.body);
final jsonResponse = {'success': false, 'response': result};
return jsonResponse;
case 401:
final jsonResponse = {
'success': false,
'response': ConstantUtil.UNAUTHORIZED
};
return jsonResponse;
case 500:
case 501:
case 502:
final jsonResponse = {
'success': false,
'response': ConstantUtil.SOMETHING_WRONG
};
return jsonResponse;
default:
final jsonResponse = {
'success': false,
'response': ConstantUtil.SOMETHING_WRONG
};
return jsonResponse;
}
} on SocketException {
final jsonResponse = {
'success': false,
'response': ConstantUtil.NO_INTERNET
};
return jsonResponse;
} on FormatException {
final jsonResponse = {
'success': false,
'response': ConstantUtil.BAD_RESPONSE
};
return jsonResponse;
} on HttpException {
final jsonResponse = {
'success': false,
'response': ConstantUtil.SOMETHING_WRONG //Server not responding
};
return jsonResponse;
}
}
Call this function and use response I'm calling it in init method of statefulWidget.
#override
void initState() {
// TODO: implement initState
super.initState();
final result = await requestGET('google.com');
if (result['success'] == false) {
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error"),
content: Text(result['response']),
actions: [
FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.pop(context);
},
),
],
);
;
},
);
}
}
I think you can check the response code from the api call using http code request from this link http status code
as you can check the response from json like this:
Future<String> checkServerResponse() await
{
http.Response response =
await http.get('server_link'):
print(response.statusCode);
}
now as you can see the response code of the server based on http status code.

How to use response after POST Request?

How to use data from response after POST request in Flutter/Dart?
this is my function:
signIn(String email, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email': email,
'password': pass
};
var jsonResponse = null;
var response = await http.post("http://10.0.2.2:80/user/login", body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if(jsonResponse != null) {
print(jsonResponse);
setState(() {
_isLoading = true;
});
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => MainPage()), (Route<dynamic> route) => false);
}
}
else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}
after run this function, my jsonResponse returns this data to me:
{id: 1, firstName: admin, lastName: admin, accountName: Kot filemon, email: admin#admin.pl, active: false, activateCode: 0, admin: true, latitude: xxx, longitude: xxx, profileImage: null}
so, how can I use this data(without another request to server) in my app on different screen?
I know how to use this type of data in react, because i'm a frontend developer but i don't have any idea how to use this here.
thanks for any help :)
You can save it to SharedPreferences if all the data in this response are common for all screens.
At this moment you cant store all that jsondata in one SharedPreferenceValue. You need to create one value foreach userdata like this:
signIn(String email, pass) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
Map data = {
'email': email,
'password': pass
};
var jsonResponse = null;
var response = await http.post("http://10.0.2.2:80/user/login", body: data);
if(response.statusCode == 200) {
jsonResponse = json.decode(response.body);
if(jsonResponse != null) {
print(jsonResponse);
// this lines save the user data in the sharedpreferenceinstance
await prefs.setString('email',jsonResponse[email]);
await prefs.setString('accountName', jsonResponse[accountName]);
//-----------------now you cant send to another page
// if you need to read the saved data use=>prefs.getInt('email');
setState(() {
_isLoading = true;
});
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => MainPage()), (Route<dynamic> route) => false);
}
}
else {
setState(() {
_isLoading = false;
});
print(response.body);
}
}