Sorry for the (seemingly) lazy question, but i've been looking for a solution with no luck (in other words, I haven't found a solution that i understand).
I want to have users log in to an app by way of entering a username and password, this username and password has to match a username and password from the jsonarray which i've retrieved from a phpmyadmin database. The username and password have to be in the same row.
Here's the function I use to retrieve my jsonarray:
private void getData(){
JSONArray json;
try{
user = editText1.getText().toString();
password = editText2.getText().toString();
json = readJsonFromUrl("http://localhost/indextest.php?function=getdata");
Thread.sleep(1000);
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
}
I just need to know how to search the jsonarray for the values that i retrieve from my textviews.
If possible I would like to retrieve a value that I can easily assign to an if statement like such:
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
if ( editText1 != null && editText1.length() != 0 && editText2 != null && editText2.length() != 0){
getData();
m_ProgressDialog = ProgressDialog.show(HomeScreen.this,
"Please wait...", "Checking Details...", true);
m_ProgressDialog.setCancelable(true);
if ( /*username and password match*/){
Intent i = new Intent(this, Afterlog.class);
startActivity(i);
}
else{
Toast.makeText(HomeScreen.this, "The username and password did not match any in our database...", Toast.LENGTH_SHORT).show();
}
}
else {
Toast.makeText(HomeScreen.this, "Please enter a user name AND a password...", Toast.LENGTH_SHORT).show();
}
break;
}
}
Two things:
Take a look at GSON. It is a Google Library for encoding objects into json and then decoding json into objects. In essence, you can define a class that has the same structure as the data you are receiving in JSON and then use GSON to read the JSON and create an object of your class with the appropriate fields filled in. Your code would look something like this:
First, define your class structure for the data you are sending as JSON:
public class LoginData {
public String Username; //These identifiers must match the JSON structure
public String HashedPassword;
public LoginData(String username, String hashedPass) {
Username = username;
HashedPassword = hashedPass;
}
}
Then, once you receive the JSON, you can parse the information like this:
LoginData login = mGson.fromJson(json, LoginData.class);
It sounds like you are storing usernames and passwords in raw text and retrieving them from your database in raw text. This is a VERY BAD IDEA! Passwords should always be stored in an encrypted form (i.e. hashed). When the user provides their password to log in, you encrypt the provided password and compare the encrypted versions (i.e. compare the hash of the provided password to the stored hash from your database). This prevents people who might be listening to your network traffic from being able to capture your passwords. Instead, if they were watching your network traffic they would see the hashed password, and without knowing exactly the algorithm used to hash the passwords, they would not be able to calculate the original password.
Your code needs to run in an asyncTask because it is performing a network request:
Here is an example:
class LoginTask extends AsyncTask<String, String, JSONObject>
{
protected JSONObject doInBackground(String... urls)
{
return readJsonFromUrl(urls[0]);
}
protected void onPostExecute(JSONObject result)
{
try {
//this assumes that the response looks like this:
//{"username" : "john" , "password" : "Bsd6578" }
String responseUsername = result.getString("username");
String responsePassword = result.getString("password");
if (user.equals(responseUsername) && password.equals(responsePassword)){
Intent i = new Intent(this, Afterlog.class);
startActivity(i);
}else{
Log.d("mylog", "username and password dont match");
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Your button is should be responsible for running that task:
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
user = editText1.getText().toString();
password = editText2.getText().toString();
new LoginTask().execute()
break;
}
}
Found a very simple and to the point tutorial here:
http://www.coderzheaven.com/2012/04/22/create-simple-login-form-php-android-connect-php-android/
Thanks for all the help #meda :)
Related
Register Button in Register Acvtivity
public void registerBtnClicked(View view){
String email = binding.userEmailEditText.getText().toString();
String password = binding.userPasswordEditText.getText().toString();
String userNameData = binding.usernameEditText.getText().toString();
user = new Users(userNameData,email,password);
db = FirebaseDatabase.getInstance();
databaseReference = db.getReference(Users.class.getSimpleName());
databaseReference.push().setValue(user);
if(email.equals("") || password.equals("")){
Toast.makeText(this, "Enter email and password", Toast.LENGTH_LONG).show();
}else{
auth.createUserWithEmailAndPassword(email,password).addOnSuccessListener(new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Intent intent = new Intent(RegisterPage.this, MainActivity.class);
startActivity(intent);
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(RegisterPage.this, e.getLocalizedMessage(),Toast.LENGTH_LONG).show();
}
});
}
}
I created a real time database.But I couldn't figure out how to show username in navigation header section. Can you help me?
If I understand correctly, the firebaseUser is null when you're trying to read the display name from it. This is actually a common scenario, as the user's sign-in session is managed by Firebase in the background, and the current user may change at any time.
The simple fix is to check whether there is a current user before accessing their display name, which you can do with:
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) {
navUserEmail.setText(firebaseUser.getEmail());
navUserName.setText(firebaseUser.getDisplayName());
}
Note though that the display name is an optional property of the user profile, so it can indeed be null. If you want to display nothing in that case, you can do:
String displayName = firebaseUser.getDisplayName();
navUserName.setText(displayName != null ? displayName : "");
Even if you've set the display name of a user, it may take up to an hour until that is updated for all connected clients, as they all cache the user profile. And since such updates happen in the background... 👇
To correctly handle all auth state changes, you'll want to use an auth state listener, as shown in this article: https://stackoverflow.com/collectives/google-cloud/articles/68104924/listen-for-authentication-state-in-android
In android I want to make a basic login and registration application. I am following this tutorial. The application works properly and runs. I am just trying to understand the code now and after many google searches I can not understand some of the code and was wondering if somebody could help me understand it.
Below I have posted the method I do not understand and in comments highlighted what I do not understand - any clarification is much appreciated, I have also commented the code to what I believe the code does, if any of it is incorrect please tell me, you can also view all of the code on the tutorial website.
I am mainly confused about how the sharedpreferences works I have followed his tutorial on sharedpreferences too I understand that but do not understand this. Thank you and sorry if the problem is very basic
private void checkLogin(final String email, final String password) {
// Tag used to cancel the request
String tag_string_req = "req_login";
// Dialog stating trying to login
pDialog.setMessage("Logging in ...");
showDialog();
// Send the request over to the database to check details
StringRequest strReq = new StringRequest(Method.POST,
AppConfig.URL_LOGIN, new Response.Listener<String>() {
// Do this once you get a response
#Override
public void onResponse(String response) {
Log.d(loginName, "Login Response: " + response.toString());
hideDialog();
// Break the response up into individual things and store in variables
try {
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("error");
// Check for error node in json
if (!error) {
// I DO NOT UNDERSTAND THIS!!! how does this bit work?
// it sets the shared preferences login to true correct?
// but how does it set it true to only this particular user?
// Because it doesnt store the email and password along with it
// and sets its tag "isLoggedIn" and then saves it to the shared
// preferences
session.setLogin(true);
// Now store the user in SQLite
String uid = jObj.getString("uid");
JSONObject user = jObj.getJSONObject("user");
String name = user.getString("name");
String email = user.getString("email");
String created_at = user
.getString("created_at");
//I DO NOT UNDERSTAND THIS!!! Why do you need to do this & does this
//affect the MySQL DB at all?
db.addUser(name, email, uid, created_at);
// I DO NOT UNDERSTAND THIS!!! Why do you need to write LoginActivity.this
// do you not just write MainActivity?
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
startActivity(intent);
finish();
} else {
// Error in login. Get the error message
String errorMsg = jObj.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
// JSON error
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Json error: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(loginName, "Login Error: " + error.getMessage());
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_LONG).show();
hideDialog();
}
}) {
/***************************************************************/
//I DO NOT UNDERSTAND THIS WHOLE METHOD WHY DO YOU DO THIS?!!!
/***************************************************************/
#Override
protected Map<String, String> getParams() {
// Posting parameters to login url
Map<String, String> params = new HashMap<String, String>();
params.put("email", email);
params.put("password", password);
return params;
}
};
// FINALLY I ALSO DO NOT UNDERSTAND WHY YOU DO THIS! AND WHAT DOES IT DO
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
This adds a user to an SQL database:
db.addUser(name, email, uid, created_at);
There should be a class somewhere that defines the actual function, which then creates the query that actually interacts with the database.
The intent changes the activity (what is rendered on the screen and what logic is handled):
LoginActivity.this: the context in the current class - this can be simplified to just this, but it's a bit of syntactic sugar in Java that attempts to clarify which this is being referred to.
MainActivity.class: the target activity
Intent intent = new Intent(LoginActivity.this,
MainActivity.class);
The difference between two activities can be explained with the content of a game. The menu is "LoginActivity.this" and "MainActivity.class" is the actual game content
As for shared preferences, the usage is pretty straight-forward:
To obtain shared preferences, use the following method In your
activity:
SharedPreferences prefs = this.getSharedPreferences(
"com.example.app", Context.MODE_PRIVATE);
To read preferences:
String dateTimeKey = "com.example.app.datetime";
// use a default value using new Date()
long l = prefs.getLong(dateTimeKey, new Date().getTime());
To edit and save preferences
Date dt = getSomeDate();
prefs.edit().putLong(dateTimeKey, dt.getTime()).apply();
(Source, posted by naikus)
The internal mechanics aren't something you need to worry about - the thing you really need to know is that it's able to save your data in a way you can use that doesn't involve directly accessing files (which has become a maze since Android 10).
EDIT:
Based on what I saw at the tutorial, the entire thing is to check if the login information entered exists in the database. The getParams() method defines what goes into the form data
I have the following method in my Android app which I use for user login/registration.
public void registerUser(final String username, final String email, final String password) {
pDialog.setMessage("Signing Up...");
pDialog.show();
request = new StringRequest(Method.POST, SL_URL, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
pDialog.dismiss();
String[] split = s.split("Config.php");
String after = split[1];
try {
JSONObject jsonObject = new JSONObject(after);
boolean error = jsonObject.getBoolean("error");
if (error) {
String errorMsg = jsonObject.getString("error_msg");
Toast.makeText(getApplicationContext(),
errorMsg, Toast.LENGTH_LONG).show();
} else {
session.setLogin(true, username, email);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("tag", "login");
hashMap.put("username", name);
hashMap.put("password", password);
return hashMap;
}
};
queue.add(request);
}
Now I am writing my app for iOS and trying to replicate this in Swift. So far I have the following code:
let username = usernameTxt.text
let password = passwordTxt.text
let urlPath: String = "***"
let url: NSURL = NSURL(string: urlPath)!
let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request1.HTTPMethod = "POST"
let stringPost="tag=login&username=" + username! + "&password=" + password! // Key and Value
NSLog(stringPost)
let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)
request1.timeoutInterval = 60
request1.HTTPBody=data
request1.HTTPShouldHandleCookies=false
let queue:NSOperationQueue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
do {
var jsonResult: NSDictionary = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch _ {}
})
Now as someone new to iOS development and Swift in general, I have the following questions:
What is the best way to replicate the progressDialog I use in Java in Swift, it must be visible until the request is complete and then it should be dismissed. I'm guessing this should be placed in the completionHandler, however I'm not sure which UI element to use for the progress Dialog.
How do I obtain my response as a String and replicate the behaviour of the split function, and then convert the result of this into a jsonObject like I do in my Java code.
What is the best way to replicate the Toast used to show the error message. I don't think using a dialog which must be closed with a button would be optimal here.
Thank you.
I am also developing Applications for Android and IOS. Here i Answered your three Problems which is faced by me also as a beginner. I hope this would help you.
1) Use MBProgressHUD Link to replicate the progressDialog in Swift .There are two method to show and dismiss the progressDialog:
Use showLoadingHUD() before making HTTP request
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
hud.labelText = "Loading..."
}
And hideLoadingHUD() after receiving the response from server
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
}
2) you can use Alamofire Link which can handle Network stuff And you can easily obtain response in String.
Example:
self.showLoadingHUD()
Alamofire.request(.GET, data, parameters: nil)
.response { (request, response, data, error) in
print(data) // if you want to check data in debug window.
let Result = NSString(data: data!, encoding: NSUTF8StringEncoding)
Result!.stringByReplacingOccurrencesOfString("\"", withString: "")
if(newResult == "1"){
self.navigationController!.popViewControllerAnimated(true)
JLToast.makeText("Success").show()
}
else if (newResult == "0"){
JLToast.makeText("Failed").show()
}
self.hideLoadingHUD()
3) mankee Toas are used for a purpose of displaying information for short period of time and disappear themselves. Here we can use Android like Toast which is JLToast. Available on github .
JLToast.makeText("Success").show()
I'm trying to login using Parse for android.
If I enter the correct username and password, I log in successfully.
But when I use a wrong password or username, I always get error 101: object not found.
Here's the code (Notice "username" and "password" are EditText):
private void doLogin() {
if (!validate()) { // IF VALIDATION FAILS, DO NOTHING
return;
} // ELSE...
String name = email.getText().toString();
String pass = password.getText().toString();
ParseUser.logInInBackground(name, pass, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
goToMainActivity(user.getUsername());
} else {
handleParseError(e);
}
}
});
}
Thanks for your help.
Update: Parse does not have means to check if there was an incorrect login field. Hence they use the general 101: Object Not Found error to catch it. Reference: https://parse.com/docs/android/api/com/parse/ParseException.html
Previous stackoverflow link: Parse : invalid username, password
If you want your app to respond to an incorrect login, just replace the line handleParseError(e); with code to handle it.
For example, if you want a message box to show up, place that code there. If you do not want to do anything, comment out that line. Not sure what else you are looking for...
I would suggest replacing it with a Toast message
I am using Android Studio for my app and Parse for my database... and on the create an account page I have, it allows the user to enter in first name, last name, email, username, and password.
But my code is using parseUser... I don't know how to set the first and last name in the database.
I know setUsername, setPassword, setEmail is a part of it... but what about if you make a column in Parse? How can you add this in your class?
This is a part of my code, what it looks like...my problem is in the else statement I have:
// Force user to fill up the form
if (usernametxt.equals("") && passwordtxt.equals("") && emailtxt.equals("")) {
Toast.makeText(getApplicationContext(),
"Please fill in the username, password, and email fields.",
Toast.LENGTH_LONG).show();
} else {
// Save new user data into Parse.com Data Storage
ParseUser user = new ParseUser();
//somehow save first and last name
user.setEmail(emailtxt);
user.setUsername(usernametxt);
user.setPassword(passwordtxt);
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
Yes, Parse does provide methods to save username, passwords like setUsername(params) and setPassword(params) but if you want to add more data to the tables, you can create more columns according to your needs as I did in this code snippet.
If you have come columns created already in parse back-end like name, phone,address,cityState,companyId, this is how I am doing it.
private void savetoParse() {
ParseUser user = new ParseUser();
user.setUsername(usernameEditText.getText().toString());
user.setPassword(passEditText.getText().toString());
user.put("name", nameEditText.getText().toString());
user.setEmail(emailEditText.getText().toString());
user.put("phone", phoneNoEditText.getText().toString());
user.put("address", addressEditText.getText().toString());
user.put("cityState", cityStateEditText.getText().toString());
user.put("companyID", compSchoolIdEditText.getText().toString());
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(ParseException e) {
if (e != null) {
Toast.makeText(SignupActivityUpdate.this,
"Saving user failed.", Toast.LENGTH_SHORT).show();
Log.w(TAG,
"Error : " + e.getMessage() + ":::" + e.getCode());
if (e.getCode() == 202) {
Toast.makeText(
SignupActivityUpdate.this,
"Username already taken. \n Please choose another username.",
Toast.LENGTH_LONG).show();
usernameEditText.setText("");
passEditText.setText("");
confirmPassEditText.setText("");
}
} else {
Toast.makeText(SignupActivityUpdate.this, "User Saved",
Toast.LENGTH_SHORT).show();
/*Do some things here if you want to.*/
}
}
});
NOTE : The first params is the column name and second is the value. So, it basically acts like a key value pair.
This is solve the problem..lemme know if this works..good luck..:)
/**
* user Registration here
* save user registration value on server here
*/
private void userRegistration()
{
progressDialog=new ProgressDialog(SignUpThirdPage.this);
progressDialog.setMessage("Please Wait......");
progressDialog.setCancelable(false);
progressDialog.show();
ParseUser user = new ParseUser();
user.setUsername("Name");
user.setPassword(strPassword);
user.setEmail(strEmailId);
// surName column create on parse.com db you can check after run that code
// like that u can add more column in signup table
user.put("surName","Kumar");
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(com.parse.ParseException e) {
// TODO Auto-generated method stub
if (e == null) {
}
} else {
// Sign up didn't succeed. Look at the ParseException
// to figure out what went wrong
e.printStackTrace();
progressDialog.dismiss();
if(e.getMessage().contains("already taken")){
alertDialog("", "you've already sign up , lets login in ", SignUpThirdPage.this, false);
}
else if(e.getMessage().contains("has already been taken")){
alertDialog("", "you've already sign up , lets login in ", SignUpThirdPage.this, false);
}
else {
AppConstants.showAlertDialog("", e.getMessage(), SignUpThirdPage.this, false);
}
}
}
});
}