I'm having troubles with creating users in my app, I get an error that says I don't have sufficient permissions even though I should have permission. My security rules are allowing users to be created so I don't really understand why I am getting this error. What's even more strange is that it works on my mates computer, he can create users (with the exact same userdetails). He is on a pc and I on a mac not sure if that matters?
The error I get is the following:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: PlatformException(Error 7, FIRFirestoreErrorDomain, Missing or insufficient permissions.)
Our security rules are:
service cloud.firestore {
//match /databases/{database}/documents {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
match /Users/{userId} {
allow update: if request.auth.uid == userId;
}
match /Users/{document=**} {
allow create;
}
match /Recipes/{document=**} {
allow create: if request.auth != null;
allow update, delete: if request.resource.data.userId == request.auth.uid;
}
match /Recipes/{document=**}/newRatings {
allow create, update: if request.auth != null;
}
}
} ```
Our code for registering users is:
´´´ import 'package:cibus/pages/loginScreens/username_screen.dart';
import 'package:cibus/pages/loginScreens/verify_screen.dart';
import 'package:cibus/services/colors.dart';
import 'package:flutter/material.dart';
import 'package:cibus/services/login/auth.dart';
import 'package:cibus/services/constants.dart';
import 'package:cibus/pages/loginScreens/e-sign_in_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_user_stream/firebase_user_stream.dart';
import 'package:cibus/services/my_page_view.dart';
import 'package:provider/provider.dart';
import 'package:cibus/services/login/user.dart';
import 'package:cibus/services/database.dart';
import 'package:cibus/pages/loading_screen.dart';
const registerButtonColor = kTurquoise;
const formSizedBox = SizedBox(height: 20.0);
const EdgeInsets formPadding =
EdgeInsets.symmetric(vertical: 10.0, horizontal: 50.0);
const TextStyle textStyleErrorMessage =
TextStyle(color: Colors.red, fontSize: 14.0);
const TextStyle textStyleRegisterButton = TextStyle(color: Colors.white);
OutlineInputBorder textInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
);
class RegisterScreen extends StatefulWidget {
final Function toggleView;
RegisterScreen({this.toggleView});
#override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
bool isVerified = false;
//final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
//text field state
String email = '';
String password = '';
String error = '';
String name = '';
String description = '';
String _currentUsername;
int age = 0;
int dropdownValue = null;
final TextEditingController _pass = TextEditingController();
final TextEditingController _confirmPass = TextEditingController();
#override
Widget build(BuildContext context) {
return loading
? LoadingScreen()
: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
elevation: 0.0,
title: Text('Sign up to Cibus', style: TextStyle(color: kCoral)),
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person, color: kCoral),
label: Text('Sign in', style: TextStyle(color: kCoral)),
onPressed: () {
//widget.toggleView();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return EmailSignIn();
},
),
);
},
),
],
),
body: Padding(
padding: formPadding,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
formSizedBox,
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Email',
),
validator: (val) =>
val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Password',
),
obscureText: true,
controller: _pass,
validator: (String val) {
Pattern pattern =
r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$';
RegExp regex = new RegExp(pattern);
print(val);
if (val.isEmpty) {
return 'Please enter password';
} else if (val.length < 8) {
return 'Minimum 8 characters required';
} else if (!val.contains(RegExp(r'[A-Z]'))) {
return 'One upper case letter required.';
} else if (!val.contains(RegExp(r'[a-z]'))) {
return 'One lower case letter required.';
} else if (!val.contains(RegExp(r'[0-9]'))) {
return 'One digit required.';
} else if (!val
.contains(RegExp(r'[!##$%^&*(),.?":{}|<>]'))) {
return 'One special character required.';
} /*
else {
if (!regex.hasMatch(val))
return 'Enter valid password: \n'
'Password must contain at least one upper case letter. \n'
'Password must contain at least one lower case letter. \n'
'Password must contain at least one digit. \n'
'Password must contain at least one special character.'; */
else
return null;
//}
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: ' Re-enter Password',
),
obscureText: true,
controller: _confirmPass,
validator: (String val) {
if (val.isEmpty)
return 'Re-enter password field is empty';
if (val != _pass.text)
return 'passwords do not match';
return null;
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Name',
),
validator: (val) =>
val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Description',
),
minLines: 5,
maxLines: 10,
validator: (val) =>
val.isEmpty ? 'Enter your description' : null,
onChanged: (val) {
setState(() => description = val);
},
),
formSizedBox,
TextFormField(
maxLength: 20,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Username',
),
validator: (val) {
if (val.length < 3)
return 'Username must be more than 2 characters';
/*else if (checkUsername == false)
return 'Username is allready taken';*/
return null;
},
onChanged: (val) {
setState(() {
_currentUsername = val;
print(_currentUsername);
});
}),
formSizedBox,
RaisedButton(
color: kCoral,
child: Text('Register', style: textStyleRegisterButton),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
bool isUsernameFree = await DatabaseService()
.isUsernameTaken(username: _currentUsername);
print(' checkUsername: $isUsernameFree');
if (!isUsernameFree) {
dynamic result =
await _auth.registerWithEmailAndPassword(
email, password, name, description, age);
if (result == null) {
setState(() {
error = 'Email is already registered';
_verificationEmailDialog();
});
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return VerifyScreen();
},
),
);
}
} else {
setState(() {
error = 'Username is already taken';
});
_usernameDialog();
}
}
},
),
Text(
error,
style: textStyleErrorMessage,
),
])),
),
));
}
Future<void> _usernameDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Username is already taken'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like your username is allready taken. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
Future<void> _verificationEmailDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Email is already in use'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like the email is already in use. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
}
and here is the registerWithEmailAndPassword function:
Future registerWithEmailAndPassword(String email, String password,
String name, String description, int age) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
user.sendEmailVerification();
user.isEmailVerified;
print('Email verification sent?');
//create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData(name: name, description: description, age: age);
await DatabaseService(uid: user.uid).updateUserPicture(
pictureURL:
'https://firebasestorage.googleapis.com/v0/b/independent-project-7edde.appspot.com/o/blank_profile_picture.png?alt=media&token=49efb712-d543-40ca-8e33-8c0fdb029ea5');
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
It was a mistake on my part with the Security rules. I had that users could create users but they could only read if they were authenticated, so when I checked if username was taken the error occurred since I did not have the read permissions. I just added the read part on users and it works
match /Users/{document=**} {
allow create: if true;
allow read: if true;
}
´´´
Related
I am working with Firebase authentication and lately was not able to do anything because of the following error. When I enter the user's credentials, it gets authenticated on the Firebase console, but my app's screen does not change. What's more, the following error appears in debug console.
2 I/System.out(26261): (HTTPLog)-Static: isSBSettingEnabled false
I/SurfaceControl(26261): nativeRelease nativeObject
s[-5476376676702711408] I/SurfaceControl(26261): nativeRelease
nativeObject e[-5476376676702711408] W/System (26261): Ignoring
header X-Firebase-Locale because its value was null. 2
I/System.out(26261): (HTTPLog)-Static: isSBSettingEnabled false
void authUser(
String email, String password, String conPassword, bool isLogin) async {
UserCredential authResult;
setState(() {
isLoading = true;
});
FocusScope.of(context).unfocus();
try {
if (password != conPassword && isLogin == false) {
showDialog(
context: context,
builder: (_) => const AlertDialog(
title: Text('Passwords don\'t match'),
content: Text('Please check if your passwords match'),
),
);
}
if (isLogin == false) {
authResult = await firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
} else {
authResult = await firebaseAuth.signInWithEmailAndPassword(
email: email,
password: password,
);
}
setState(() {
isLoading = false;
});
} catch (e) {
rethrow;
}
}
...
TextFormField(
key: const ValueKey('email'),
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
label: Text('Email adress'),
),
onSaved: (newValue) {
email = newValue!;
FocusScope.of(context).requestFocus(_passwordNode);
},
),
TextFormField(
key: const ValueKey('password'),
focusNode: _passwordNode,
obscureText: true,
onSaved: (newValue) {
password = newValue!;
FocusScope.of(context).requestFocus(_conPasswordNode);
},
decoration: const InputDecoration(
label: Text('Password'),
),
),
if (isLogin == false)
TextFormField(
key: const ValueKey('conPassword'),
focusNode: _conPasswordNode,
obscureText: true,
decoration: const InputDecoration(
label: Text('Confirm password'),
),
onSaved: (newValue) {
conPassword = newValue!;
},
),
Expanded(
child: Container(),
),
widget.isLoading == true
? const Center(
child: CircularProgressIndicator(),
)
: ButtonBar(
alignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
setState(() {
isLogin = !isLogin;
});
},
child: Text(isLogin == true ? 'SignUp' : 'Login'),
),
ElevatedButton(
onPressed: _trySubmit,
child: const Text('Done'),
),
],
),
...
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Firebase.initializeApp(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (ctx) => RecipeProvider(),
),
],
child: MaterialApp ...
home: StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasData) {
return AllRecipesScreen();
}
return AuthScreen();
}),
routes: {
AllRecipesScreen.routeName: (ctx) => AllRecipesScreen(),
RecipeDetailScreen.routeName: (ctx) => RecipeDetailScreen(),
AddRecipeScreen.routeName: (ctx) => AddRecipeScreen(),
AuthScreen.routeName: (ctx) => AuthScreen(),
},
),
);
});
}
}
try changing the targetedSdk to 27, hope this helps.
The code seems to be quite incomplete to conclude anything out of it.
And as much as I know the logs that you have provided are not errors , it is just that way and are printed every-time. I don't think your main issue seems to be firebase authentication. It may be an issue of navigation(or a wrapper if you're using one).
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()
Where create call Firebase.initializeApp() ?
what should I change in my code? Is there any way to do it? In case you want to see the code please let me know I will update more.
auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:quiz2/model/user.dart';
class AuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
UserFire _userFromFirebase(User user){
return user != null ? UserFire(uid: user.uid):null;
}
Future signInEmailAndPass(String email, String password) async {
try {
UserCredential authResult = await _auth.signInWithEmailAndPassword(
email: email, password: password);
User firebaseUser = authResult.user;
return _userFromFirebase(firebaseUser);
} catch (e) {
print(e.toString());
}
}
Future signUpWithEmailAndPassword(String email, String password) async{
try{
UserCredential authResult = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User firebaseUser = authResult.user;
return _userFromFirebase(firebaseUser);
}catch(e){
print(e.toString());
}
}
Future signOut() async{
try{
return await _auth.signOut();
}catch(e){
print(e.toString());
return null;
}
}
}
signup.dart
import 'package:flutter/material.dart';
import 'package:quiz2/database/auth.dart';
import 'package:quiz2/screens/landing.dart';
import 'package:quiz2/screens/signin.dart';
import 'package:quiz2/widgets/widget.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
final _formKey = GlobalKey<FormState>();
String email, password, name;
AuthService authService = new AuthService();
bool _isLoading = false;
signUp() async {
if (_formKey.currentState.validate()) {
setState(() {
_isLoading = true;
});
authService.signUpWithEmailAndPassword(email, password).then((val) {
if (val != null) {
setState(() {
_isLoading = false;
});
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => MyHomePage()));
}
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: appBar(context),
backgroundColor: Colors.transparent,
elevation: 0.0,
brightness: Brightness.light,
),
body: _isLoading
? Container(child: Center(child: CircularProgressIndicator()))
: Form(
key: _formKey,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
Spacer(),
TextFormField(
validator: (val) {
return val.isEmpty ? 'Enter Name' : null;
},
decoration: InputDecoration(hintText: 'Name'),
onChanged: (val) {
name = val;
},
),
SizedBox(
height: 6,
),
TextFormField(
validator: (val) {
return val.isEmpty ? 'Enter Email' : null;
},
decoration: InputDecoration(hintText: 'Email'),
onChanged: (val) {
email = val;
},
),
SizedBox(
height: 6,
),
TextFormField(
obscureText: true,
validator: (val) {
return val.isEmpty ? 'Enter password' : null;
},
decoration: InputDecoration(hintText: 'Password'),
onChanged: (val) {
password = val;
},
),
SizedBox(
height: 24,
),
GestureDetector(
onTap: () {
signUp();
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(
color: Colors.teal,
borderRadius: BorderRadius.circular(30)),
alignment: Alignment.center,
width: MediaQuery.of(context).size.width - 48,
child: Text(
"Sign Up",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
SizedBox(
height: 18,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Alredy have an account?",
style: TextStyle(fontSize: 16),
),
GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SignIn()));
},
child: Text(" Sign In",
style: TextStyle(
fontSize: 16,
decoration: TextDecoration.underline)))
],
),
SizedBox(
height: 80,
),
],
)),
),
);
}
}
user.dart
class UserFire{
String uid;
UserFire({this.uid});
}
what should I change in my code? Is there any way to do it? In case you want to see the code please let me know I will update more.
You need initialize your firebase .Do as follows:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
Did you complete all the installation steps?
if you answer is yes :
you must check this link
In my App I have to implement a SignUpScreen.
Everything works fine but one thing not. When someone wants to sign up he cannot use the same email like a other users, this works, but I want also that he cannot use the same username. I have a collection which is called 'SerX' and a document field which is called 'Username:' in cloud firestore. If anyone knows how to do that please comment your solution.
There should be a return like this return 'This username already exists!';
Widget _buildUserNameTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Username',
style: kLabelStyle,
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
decoration: kBoxDecorationStyle,
height: 60.0,
child: TextFormField(
keyboardType: TextInputType.text,
validator: (input) {
if (input.isEmpty) {
return 'Please enter a username';
}
if(input.length < 6){
return 'Your username needs to be at least 6 characters';
}else if(input.length > 12){
return 'Your username needs to be at most 12 characters';
}
if (!RegExp(
r'^[a-zA-Z0-9]+$')
.hasMatch(input)) {
return 'Please enter a valid username.';
}
},
onSaved: (input) => _Username = input,
style: TextStyle(
color: Colors.black,
fontFamily: 'Orbitron',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.supervised_user_circle,
color: Colors.black,
),
hintText: 'Enter your Username',
hintStyle: kHintTextStyle,
),
),
),
],
);
}
Here is a simple function for checking if the username is already exists on client side.
var _instance = Firestore.instance;
Future<bool> userExists(String username) async =>
(await _instance.collection("users").where("username", isEqualTo: username).getDocuments()).documents.length > 0;
Client side check is not a secure solution. You should use Cloud Functions for Firebase for it.
I don't know if it is the perfect solution but it works for me.
doesUserExist(currentUserName) async {
try {
// if the size of value is greater then 0 then that doc exist.
await FirebaseFirestore.instance
.collection('Users')
.where('email', isEqualTo: currentEmail)
.get()
.then((value) => value.size > 0 ? true : false);
} catch (e) {
debugPrint(e.toString());
}
}
var formKey = GlobalKey<FormState>();
var username = TextEditingController();
var password = TextEditingController();
Future<bool> userExists(username , password) async {
return await FirebaseFirestore.instance.collection('users')
.where('username', isEqualTo: username)
.where('password', isEqualTo: password)
.get()
.then((value) => value.size > 0 ? true : false);
}
login() async {
bool result = await userExists(username.text.toString(),
password.text.toString());
// ignore: unrelated_type_equality_checks
if(result == true){
Navigator.push(
context, MaterialPageRoute(builder: (context) => Home()));
}else{
password.text = '';
Fluttertoast.showToast(msg: "Incorrect Username or Password", toastLength:
Toast.LENGTH_LONG);
}
}
I get ERROR_INVALID_EMAIL when I try to login to firebase but if I replaced _email and _password with the real email and pass from firebase I get Log In FirebaseUser(Instance of 'PlatformUser')
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Login extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginState();
}
}
class LoginState extends State<Login> {
final GlobalKey<FormState> formState = GlobalKey<FormState>();
String _email;
String _password;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
centerTitle: true,
backgroundColor: Colors.deepOrange,
),
body: ListView(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Form(
key: formState,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
icon: Icon(Icons.email),
hintText: 'Enter Your E-mail',
),
validator: (val) {
if (val.isEmpty) {
return 'Please Enter Your E-mail Address';
}
;
},
onSaved: (val) {
_email = val;
},
),
TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.vpn_key),
hintText: 'Enter Your Password',
),
validator: (val) {
if (val.isEmpty) {
return 'Enter Your Password';
} else if (val.length < 6) {
return 'Your Password need to be at least 6 characters';
}
;
},
onSaved: (val) {
_password = val;
},
),
RaisedButton(
child: Text('Login'),
onPressed: () async {
final formdata = formState.currentState;
if (formdata.validate()) {
final FirebaseAuth _auth = FirebaseAuth.instance;
formdata.save();
AuthResult result = await _auth.signInWithEmailAndPassword(
email: _email, password: _password)
.catchError((error) => print(error.code));
if (result != null) {
FirebaseUser user = result.user;
if (user != null) {
print('Log In: $user');
}
;
}
;
}
;
},
color: Colors.deepOrange,
textColor: Colors.white,
),
],
),
),
),
],
),
),
],
),
);
}
}
i have updated My question i have provided full code why i'm getting message of invalid email should i remove strings at first or remove _email _password from string
i have developed an login page,if the email and password matches from the database it successfully login's and moves to the new page,but if its wrong i want to display an error message email or password doesn't match.
Here's my code:
class _AdminLoginState extends State<AdminLogin> {
String _username, _password;
TextEditingController _email = TextEditingController();
final GlobalKey<FormState> _formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LOGIN'),
backgroundColor: Colors.indigo[900],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 50),
child: SizedBox(
height: 150.0,
width: 300,
child: Image.asset("assets/admin.png",
fit: BoxFit.contain,),
),
),
Container(
child: Text("ADMIN",style: TextStyle(fontSize: 15,fontWeight: FontWeight.bold,color: Colors.indigo),),
),
Container(
padding: const EdgeInsets.only(bottom: 50),
child: Column(
children: <Widget>[
SingleChildScrollView(
child: Form(
key: _formkey,
child: Column(
children: <Widget>[
SizedBox(
height: 60,
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: false,
keyboardType: TextInputType.emailAddress,
validator:(input){
if(input.isEmpty){
return 'please type username';
}
return null;
},
onSaved: (input) => _username =input ,
decoration: InputDecoration(
labelText: 'Email',
hintText: "Email",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 400,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: true,
validator:(input){
if(input.isEmpty){
return 'please type Password';
}
return null;
},
onSaved: (input) => _password =input ,
decoration: InputDecoration(
labelText: 'Password',
hintText: "Password",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: RaisedButton(
onPressed: login,
textColor: Colors.white,
color: Colors.indigo[900],
child: Text('Login'),
),
)
],
),
),
),
],
),
),
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
print(e.message);
}
}
}
}
it will be really helpful if someone also helps me in validating the right email format and give give the proper validation for password
signInWithEmailAndPassword() returns an exception with a special code if the attempt is unsuccessful.
In order to print a message you need to add a catch block to your signInWithEmailAndPassword() method. Then you can use the error message.
Example:
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
alert('Wrong password.');
} else {
alert(errorMessage);
}
console.log(error);
});
For security purposes I would suggest combining some of the messages together instead of giving a possible attacker a hint about if the email is already in the system or not.
I do not know how to use flutter so I can only give an idea;
In here you are directly trying to get the user from the method.
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Instead I would suggest using something like this (this is angular but I think you can easily apply to flutter with some modification)
final FirebaseUser user;
await firebase.auth().signInWithEmailAndPassword(email, password)
.then((data) => {
this.user = data.user;
})
.catch((error) => {
switch (error.code) {
case "auth/invalid-email":
case "auth/wrong-password":
case "auth/user-not-found":
{
this.accountErrorMessage = "Wrong email address or password.";
break;
}
case "auth/user-disabled":
case "user-disabled":
{
this.accountErrorMessage = "This account is disabled";
break;
}
}
You can find which kind of errors it may return from here:
https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#signinwithemailandpassword
Use errortext in InputDecoration
here is demo
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'email',
errorText: loginfail ? 'email not match' : null,
),
),
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'password',
errorText: loginfail ? 'password not match' : null,
),
),
RaisedButton(
onPressed: () {
login();
},
child: Text('Submit'),
textColor: Colors.white,
color: Colors.blueAccent,
)
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
if(!user.uid.isEmpty()){
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}else{
setState((){
loginfail = true; //loginfail is bool
});
}
}catch(e){
print(e.message);
}
}
hope it helps..
Following #Jaydeepchatrola answer's
I used a try catch block and checked if password was invalid or email, for better results!
try {
setState(() {
wrongEmail = false;
wrongPassword = false;
});
final newUser = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, Done.id);
}
} catch (e) {
print(e.code);
if (e.code == 'ERROR_WRONG_PASSWORD') {
setState(() {
wrongPassword = true;
});
} else {
setState(() {
emailText = 'User doesn\'t exist';
passwordText = 'Please check your email';
wrongPassword = true;
wrongEmail = true;
});
}
}
You need to catch the specific error. I had the problem by myself, with this code I solved the problem.
try {
final user = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (user != null) {
Navigator.pushNamed(context, HomeScreen.id);
}
} on auth.FirebaseAuthException catch (e) {
//Here you catch the specific error
if (e.code == 'wrong-password') {
//The thing that should happen if the password is incorrect
//In my case it will the change the hinttext
setState(() {
hintTextPassword = 'Password incorrect. Please try again';
passwordHintColor = Colors.red;
});
} else if (e.code == 'user-not-found') {
setState(() {
hintTextEmail = 'No user found for that email.';
emailHintColor = Colors.red;
});
}
} catch (e) {
print(e);
}
add rflutter_alert: ^2.0.4 in your project file pubspec.yaml under dependencies: and save it
add import 'package:rflutter_alert/rflutter_alert.dart'; in your file of your auth screen
add
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
in catch(e){}
like that:
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
}
}