Login from Flutter into Django Framework always showing Invalid Password - flutter

I am trying to login from Flutter to my Django Rest Framework but I am always getting the same error Invalid Password although the credentials are correct.
Here is the login_request_model.dart:
class LoginRequestModel {
LoginRequestModel({
this.username,
this.email,
this.password,
});
late final String? username;
late final String? email;
late final String? password;
LoginRequestModel.fromJson(Map<String, dynamic> json) {
username = json['username'];
email = json['email'];
password = json['password'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['username'] = username;
_data['email'] = email;
_data['password'] = password;
return _data;
}
}
Here is the login_page.dart:
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool isApiCallProcess = false;
bool hidePassword = true;
GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
String? userName;
String? password;
#override
void initState() {
super.initState();
}
Rest of the login_page.dart where login is inserted:
Center(
child: FormHelper.submitButton(
"Login",
() {
if (validateAndSave()) {
setState(() {
isApiCallProcess = true;
});
LoginRequestModel model = LoginRequestModel(
username: userName,
password: password,
);
APIService.login(model).then(
(response) {
setState(() {
isApiCallProcess = false;
});
if (response) {
Navigator.pushNamedAndRemoveUntil(
context,
'/home',
(route) => false,
);
} else {
FormHelper.showSimpleAlertDialog(
context,
Config.appName,
"Invalid Username/Password !!",
"OK",
() {
Navigator.of(context).pop();
},
);
}
},
Here is the login_response_model.dart:
class LoginResponse {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponse({this.key, this.non_field_errors});
factory LoginResponse.fromJson(mapOfBody) {
return LoginResponse(
key: mapOfBody['key'],
non_field_errors: mapOfBody['non_field_errors'],
);
}
}
LoginResponseModel loginResponseJson(String str) =>
LoginResponseModel.fromJson(json.decode(str));
class LoginResponseModel {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponseModel({this.key, this.non_field_errors});
LoginResponseModel.fromJson(mapOfBody) {
key:
mapOfBody['key'];
non_field_errors:
mapOfBody['non_field_errors'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['key'] = key;
_data['non_field_errors'] = non_field_errors;
return _data;
}
}
class Data {
Data({
required this.username,
required this.email,
required this.date,
required this.id,
required this.key,
});
late final String username;
late final String email;
late final String date;
late final String id;
late final String key;
Data.fromJson(Map<String, dynamic> json) {
username = json['username'];
email = json['email'];
date = json['date'];
id = json['id'];
key = json['key'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['username'] = username;
_data['email'] = email;
_data['date'] = date;
_data['id'] = id;
_data['key'] = key;
return _data;
}
}
In my django rest framework I am getting Bad Request: /api/dj-rest-auth/login/
My question:
As there is not specific error that I am trying to fix, I want to know how can I spot the error by debugging I need an example of how to try and catch error. Is there something wrong with my LoginRequestModel or LoginResponseModel

it is usually a mismatch error, try to check the following
check if the data you are sending from your flutter side, is being recieved accurately from the django side. like for example, if the backend accepts the data like this..
{
"username" : "user",
"password" : "password"
}
and you are sending the data from flutter side like this..
{
"email" : "user",
"password" : "password"
}
it expects a key of username and is receiving an email, then its a bad request
I'm not sure about django being case sensitive, but sending the data as Username instead of username.. this results in a bad request response.
so in short, to debug this.. convert the data you are sending to json and see how the data is being sent.. and check from the django side how its being received.

Related

How to solve the problem with types in flutter?

I have an array of elements that come from api and I get and error from api =>
The operator '[]' isn't defined for the type of 'Country'
Response from api looks like this:
{"success":true,"list":[{"id":2,"createdAt":"2022-11-11T15:25:31.680Z","updatedAt":"2022-11-11T15:25:31.680Z","name":"Afghanistan"}]}
This is the type of an element inside list:
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name
});
}
This is my widget:
class MyWidget extends StatefulWidget {
const MyWidget({super.key});
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Country> countries = [];
Future<void> getCountries() async {
try {
final response = await _apiService.getCountries();
countries = response['list']; // [{"id": 2, "createdAt:""...}]
} catch (e) {
log(e.toString());
rethrow;
}
}
#override
void initState() {
getCountries();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container();
}
}
And if I try to call this, IDE lights me this error in country['name'] =>
final List countriesWithNames = countries.map((country) => country['name']).toList();
Or when I try to get an element from the list, like this => countries[index]['name']
response['list'] returns list of map.You need to convert into model class.
You can use this model class
class Country {
final int id;
final String createdAt;
final String updatedAt;
final String name;
const Country({
required this.id,
required this.createdAt,
required this.updatedAt,
required this.name,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'id': id});
result.addAll({'createdAt': createdAt});
result.addAll({'updatedAt': updatedAt});
result.addAll({'name': name});
return result;
}
factory Country.fromMap(Map<String, dynamic> map) {
return Country(
id: map['id']?.toInt() ?? 0,
createdAt: map['createdAt'] ?? '',
updatedAt: map['updatedAt'] ?? '',
name: map['name'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Country.fromJson(String source) =>
Country.fromMap(json.decode(source));
}
And getting from local json string
final data = response["list"] as List?;
List<Country> countries =
data?.map((e) => Country.fromMap(e)).toList() ?? [];
print(countries);

How to access token saved as a variable in different dart page in a secured storage

I have saved a token as a variable in flutter secure storage in a file called login_response_model.dart and I am trying to access it in the home screen, but I keep getting error as undefined name:
Here is the login_response_model.dart:
class LoginResponse {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponse({this.key, this.non_field_errors});
factory LoginResponse.fromJson(mapOfBody) {
return LoginResponse(
key: mapOfBody['key'],
non_field_errors: mapOfBody['non_field_errors'],
);
}
}
LoginResponseModel loginResponseJson(String str) =>
LoginResponseModel.fromJson(json.decode(str));
class LoginResponseModel {
dynamic? key;
List<dynamic>? non_field_errors;
LoginResponseModel({this.key, this.non_field_errors});
LoginResponseModel.fromJson(mapOfBody) {
key:
mapOfBody['key'];
non_field_errors:
mapOfBody['non_field_errors'];
print(mapOfBody['key']);
// Create storage
final storage = new FlutterSecureStorage();
// Write value
storage.write(key: 'Token', value: mapOfBody['key']);
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['key'] = key;
_data['non_field_errors'] = non_field_errors;
return _data;
}
}
class Data {
Data({
required this.username,
required this.email,
required this.date,
required this.id,
required this.key,
});
late final String username;
late final String email;
late final String date;
late final String id;
late final String key;
Data.fromJson(Map<String, dynamic> json) {
username = json['username'];
email = json['email'];
date = json['date'];
id = json['id'];
key = json['key'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['username'] = username;
_data['email'] = email;
_data['date'] = date;
_data['id'] = id;
_data['key'] = key;
return _data;
}
}
Here is the homescreen:
Future<User> fetchUser() async {
var url = Uri.parse(Config.apiURL + Config.userProfileAPI);
var value = storage.read(key: 'Token');
My question:
How can I access the token saved in a secured storage into the home screen?
Is there an easier and more secure way to access the token saved other than the way I have arranged it?
Use can you SharedPreference & save token here. Each time you want to use, you just need to:
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString("key_token") ?? "";
However, each time you want to use it, you again need to use async function & wait until it give you saved token. Although it doesn't take so much time & space but we need to notice this. You can init a global variable to save token whenever open app or login success. Learn more about Singleton.
Example in my app: data_instance.dart
class DataInstance {
static DataInstance _instance = new DataInstance.internal();
DataInstance.internal();
factory DataInstance() => _instance;
late String accessToken;
initPreference() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
DataInstance().accessToken = prefs.getString("key_token_haha")?? '';
}
}
In main.dart:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await DataInstance().initPreference();
runApp(const MyApp());
}

Why is GetConnect/GetX/Flutter not calling my backend and returning a null object?

I'm using get: 4.6.5
I have defined a provider
class CredentialsProvider extends GetConnect implements GetxService {
#override
void onInit() {
httpClient.defaultDecoder =
(val) => Auth.fromJson(val as Map<String, dynamic>);
httpClient.baseUrl = 'http://localhost:1337/api/';
super.onInit();
}
Future<Response<dynamic>> postCredentials(Credentials credentials) async {
return await post('auth/local', credentials);
}
}
In my binding class add it as a dependency
class LoginBinding extends Bindings {
#override
void dependencies() {
Get.lazyPut(() => CredentialsProvider());
Get.lazyPut(() => LoginController());
}
}
And register the LoginView as a route
GetPage(
name: "/login",
page: () => const LoginView(),
binding: LoginBinding(),
)
And added it to my controller
class LoginController extends GetxController {
final provider = Get.put(CredentialsProvider());
//...
}
The controller is used in my LoginView
class LoginView extends GetView<LoginController> {...}
In my MaterialButton of the LoginView I use the onPressed to call the provider and get the result object Auth and print it out as json.
onPressed: () {
var c = Credentials(
identifier: controller.emailController.text,
password: controller.passwordController.text);
controller.provider.postCredentials(c).then((value) {
var auth = value.body as Auth;
print(auth.toJson());
});
},
I generated my Auth model from JSON using the GetX cli:
class Auth {
String? jwt;
User? user;
Auth({this.jwt, this.user});
Auth.fromJson(Map<String, dynamic> json) {
jwt = json['jwt'];
user = json['user'] != null ? User?.fromJson(json['user']) : null;
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['jwt'] = jwt;
if (user != null) {
data['user'] = user?.toJson();
}
return data;
}
}
class User {
int? id;
String? username;
String? email;
String? provider;
bool? confirmed;
bool? blocked;
String? createdAt;
String? updatedAt;
User(
{this.id,
this.username,
this.email,
this.provider,
this.confirmed,
this.blocked,
this.createdAt,
this.updatedAt});
User.fromJson(Map<String, dynamic> json) {
id = json['id'];
username = json['username'];
email = json['email'];
provider = json['provider'];
confirmed = json['confirmed'];
blocked = json['blocked'];
createdAt = json['createdAt'];
updatedAt = json['updatedAt'];
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['id'] = id;
data['username'] = username;
data['email'] = email;
data['provider'] = provider;
data['confirmed'] = confirmed;
data['blocked'] = blocked;
data['createdAt'] = createdAt;
data['updatedAt'] = updatedAt;
return data;
}
}
What I get in the console is
flutter: {jwt: null}
And my localhost service is never called.
The issue was with the decoder for the request being different that for the response. So I ended up with something like this:
Future<Auth> postCredentials(Map<String, dynamic> body) async {
var response = await post(
contentType: 'application/json',
decoder: (val) => Auth.fromJson(val as Map<String, dynamic>),
"/api/auth/local",
body);
return response.body as Auth;
}
And I call this via
controller.provider.postCredentials(credentials.toJson());

Get User Model Array List

I need to get payments array in GetUserModel it returns from nodeJs api with database information
I get with this:
List? payments
Future getCurrentUser() async {
var loginDetails = await SharedService.loginDetails();
email = loginDetails?.data.email;
GetUserRequestModel model = GetUserRequestModel(email: email!);
var currentUserInfo = await APIService.getUserInfo(model);
balance = currentUserInfo.data?.balance;
payments = currentUserInfo.data?.payments; //does not working
print(payments)
}
currentUserInfo gives me everythings but I couldnt get payments array. print(payments)
gives me "Instant of payments" output how can I get payments array properly?
This is UserresponseModel:
import 'dart:convert';
GetUserResponseModel getUserResponseModelJSON(String str) =>
GetUserResponseModel.fromJson(json.decode(str));
class GetUserResponseModel {
GetUserResponseModel({
required this.message,
required this.data,
});
late final String message;
late final Data? data;
GetUserResponseModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
data = (json['data'] != null ? Data.fromJson(json['data']) : null);
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['message'] = message;
_data['data'] = data?.toJson();
return _data;
}
}
class Data {
Data({
required this.username,
required this.email,
required this.balance,
required this.date,
required this.payments,
required this.id,
});
late final String username;
late final String email;
late final int balance;
late final String date;
late final List<Payments> payments;
late final String id;
Data.fromJson(Map<String, dynamic> json) {
username = json['username'];
email = json['email'];
balance = json['balance'];
date = json['date'];
payments =
List.from(json['payments']).map((e) => Payments.fromJson(e)).toList();
id = json['id'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['username'] = username;
_data['email'] = email;
_data['balance'] = balance;
_data['date'] = date;
_data['payments'] = payments.map((e) => e.toJson()).toList();
_data['id'] = id;
return _data;
}
}
class Payments {
Payments({
required this.paymentCost,
required this.paymentDate,
required this.id,
});
late final int paymentCost;
late final String paymentDate;
late final String id;
Payments.fromJson(Map<String, dynamic> json) {
paymentCost = json['paymentCost'];
paymentDate = json['paymentDate'];
id = json['_id'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['paymentCost'] = paymentCost;
_data['paymentDate'] = paymentDate;
_data['_id'] = id;
return _data;
}
}
And this is the getUserInfo:
static Future<GetUserResponseModel> getUserInfo(
GetUserRequestModel model) async {
var loginDetails = await SharedService.loginDetails();
Map<String, String> requestHeaders = {
'Content-Type': 'application/json',
'Authorization': 'Basic ${loginDetails!.data.token}'
};
var url = Uri.http(Config.apiURL, Config.getUserInfoAPI);
var response = await client.post(
url,
headers: requestHeaders,
body: jsonEncode(model.toJson()),
);
return getUserResponseModelJSON(response.body);
}
So I think you are looking to print the payments data.
In the payments class you should add
#override
String toString() {
return "";
// Return how you want to print the data. Here you could add for example the JSON output.
}
So the class will look like this
class Payments {
Payments({
required this.paymentCost,
required this.paymentDate,
required this.id,
});
late final int paymentCost;
late final String paymentDate;
late final String id;
Payments.fromJson(Map<String, dynamic> json) {
paymentCost = json['paymentCost'];
paymentDate = json['paymentDate'];
id = json['_id'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['paymentCost'] = paymentCost;
_data['paymentDate'] = paymentDate;
_data['_id'] = id;
return _data;
}
#override
String toString() {
return "${this.paymentCost!} : ${this.paymentDate!} : ${this.id!}";
}
}
I haven't tested this code.

how to pass the model class and return data in flutter

Model class:
#JsonSerializable()
class EmpVerifyEntity extends Equatable {
#JsonKey(name: "access_token")
final String accessToken;
final EmpVerifyEmployee employee;
const EmpVerifyEntity(this.accessToken, this.employee);
factory EmpVerifyEntity.fromJson(Map<String, dynamic> json) =>
_$EmpVerifyEntityFromJson(json);
Map<String, dynamic> toJson() => _$EmpVerifyEntityToJson(this);
static const empty = EmpVerifyEntity(
'123',
EmpVerifyEmployee(
'1', 'avatar', 'sId', 'empName', 'empId', 'designation', 1));
#override
String toString() {
return jsonEncode(this);
}
#override
// TODO: implement props
List<Object?> get props => [accessToken, employee];
}
#JsonSerializable()
class EmpVerifyEmployee extends Equatable {
#JsonKey(name: "password")
final String password;
final String avatar;
#JsonKey(name: "_id")
final String sId;
#JsonKey(name: "emp_name")
final String empName;
#JsonKey(name: "emp_id")
final String empId;
final String designation;
#JsonKey(name: "__v")
final int iV;
const EmpVerifyEmployee(this.password, this.avatar, this.sId, this.empName,
this.empId, this.designation, this.iV);
factory EmpVerifyEmployee.fromJson(Map<String, dynamic> json) =>
_$EmpVerifyEmployeeFromJson(json);
Map<String, dynamic> toJson() => _$EmpVerifyEmployeeToJson(this);
static const empty = const EmpVerifyEmployee(
'password', 'avatar', 'sId', 'empName', 'empId', 'designation', 1);
#override
String toString() {
return jsonEncode(this);
}
#override
// TODO: implement props
List<Object?> get props =>
[password, avatar, sId, empName, empId, designation, iV];
}
auth repo:
class AuthenticationRepository {
Future<void> logIn({ //login process
required String username,
required String password,
}) async {
print("------------------");
print(username);
var res = await http.post(
Uri.parse("https://cots.com/api/v1/employee/login"),
headers: {
'Content-type': 'application/json',
'Accept': 'application/json'
},
body: jsonEncode({"emp_id": username, "password": password}));
dynamic data = json.decode(res.body);
print(data);
if (data['employee']["is_active"] == true) {
_controller.add(AuthenticationStatus.authenticated);///here it shows authenticated
}
}
User Repo:
class UserRepository {
EmpVerifyEntity? _empVerifyEntity;
UserRepository(this._empVerifyEntity);
Future<EmpVerifyEntity?> getUser() async {
if (_empVerifyEntity != null) {
return _empVerifyEntity;
}
}
}
Auth Bloc:
class AuthenticationBloc
extends Bloc<AuthenticationEvent, AuthenticationState> {
AuthenticationBloc({
required AuthenticationRepository authenticationRepository,
required UserRepository userRepository,
}) : _authenticationRepository = authenticationRepository,
_userRepository = userRepository,
super(const AuthenticationState.unknown()) {
on<AuthenticationStatusChanged>(_onAuthenticationStatusChanged);
on<AuthenticationLogoutRequested>(_onAuthenticationLogoutRequested);
_authenticationStatusSubscription = _authenticationRepository.status.listen(
(status) => add(AuthenticationStatusChanged(status)),
);
}
final AuthenticationRepository _authenticationRepository;
final UserRepository _userRepository;
late StreamSubscription<AuthenticationStatus>
_authenticationStatusSubscription;
#override
Future<void> close() {
_authenticationStatusSubscription.cancel();
_authenticationRepository.dispose();
return super.close();
}
void _onAuthenticationStatusChanged(
AuthenticationStatusChanged event,
Emitter<AuthenticationState> emit,
) async {
switch (event.status) {
case AuthenticationStatus.unauthenticated:
return emit(const AuthenticationState.unauthenticated());
case AuthenticationStatus.authenticated:
final user = await _tryGetUser();
return emit(user != null
? AuthenticationState.authenticated(user)
: AuthenticationState.unauthenticated());
default:
return emit(const AuthenticationState.unknown());
}
}
void _onAuthenticationLogoutRequested(
AuthenticationLogoutRequested event,
Emitter<AuthenticationState> emit,
) {
_authenticationRepository.logOut();
}
Future<EmpVerifyEntity?> _tryGetUser() async {
try {
final user = await _userRepository.getUser();
return user; /////----------------Here I'm getting null as a user
} catch (e) {
print(e);
}
}
}
I can able to do login but can't able to fetch data because it shows null, In login method I should return data so that I can able to fetch. It is authenticated but user data is null, how to pass the return data to userRepo so that I can fetch in authBloc.
-------------------------------------THank you--------------------------