I'm now trying to build the user authentication logic of a website. Now I should check, when a user tries to log in, does he have a registered email/password already. But I cannot just simply get the field's value from the DB, as a string.
In the database, I have 6 fields (isSuperuser, fullName, institution, password, email, approved). For the authentication, the unfinished method is here:
router.post("/login", async (req, res, next)=> {
const email = req.body.email;
const data = await client.query(`SELECT * FROM user_table WHERE email= $1;`, [email])
const arr = data.rows
//const arr = data.rows;
.then(user=> {
if(arr==null || arr== undefined || arr.length==0){
return res.status(401).json({
message: "Login authentication failed!"
})
}
})
})
My problem is, that, when I check, if the email, provided at login, already exists, I should simply compare it (req.body.email) with the value(s) of the email field in the database. But I did not find any solution, how to just get a string, as a result for the query. The const arr gives an array, from which I cannot get the value of the email key. So far, this code might works (though ugly as hell), but when it comes to password compare, I will bleed.
If I try
client.query("SELECT password FROM user_table WHERE email= $1;", [email])
it only gives back an empty array.
What do I do wrong? Any solution, please?
Iam not sure about PostgreSql but I know sql so give it a try;
router.post("/login", async (req, res, next) => {
const { email } = req.body;
const data = await client.query(`SELECT * FROM user_table WHERE email= ${email}`).then((result) => {
return result
})
if (!data) { // OR if data is an array then use "data.length == 0"
return res.status(401).json({
success: false,
message: "Login authentication failed!"
})
}
})
Related
I am using PostgreSQL for the first time with an express server and am running into an error. On my register user route I am trying to check if the username or email already exists, because they need to be unique. What keeps happening is, say I pass in a username that is already in the database then the first return will run and return that the username is already in use. But what is happening is it is returning the username is already in use and it still running the rest of the code so it trying to return multiple json responses.
module.exports.register = async (req, res, next) => {
try {
const { username, email, password } = req.body;
postgres
.query("SELECT * FROM users WHERE username = $1", [username])
.then((data) => {
if (data.rows.length > 0) {
return res.status(409).json({
msg: "Username is already in use",
status: false,
});
}
})
.catch((err) => {
console.log(err);
});
postgres
.query("SELECT * FROM users WHERE email = $1", [email])
.then((data) => {
if (data.rows.length > 0) {
return res.status(409).json({
msg: "Email is already in use",
status: false,
});
}
})
.catch((err) => {
console.log(err);
});
const hashedPassword = await bcrypt.hash(password, 10);
postgres.query(
"INSERT INTO users (username, email, password) VALUES ($1,$2,$3) RETURNING *",
[username, email, hashedPassword],
(err, data) => {
if (err) {
console.log(err.stack);
} else {
return res.json({ user: data.rows, status: true });
}
}
);
} catch (err) {
next(err);
}
};
I can't figure out why the rest of the code is running even though I am returning res.json. If anybody has any suggestions/solutions I would really appreciate it!
The return in front of the res.status(409) is returning you out of the then of the postgres.query function instead of the full register function. As a result it jumps out of the then and runs the rest of the code from there, so it's still hashing the password and attempting an insert into the users table (which hopefully fails on a unique index).
In order to fix this you can either 1) Define a variable before the function, change it if something was found and then do a return outside of the then statement if the variable was changed 2) perform all the rest of the code in the then statement (since you're returning out of that it will not be run) or 3) use awaits instead and throw/next+return/res.json+return an the HTTP 409 error.
Option 3 will take the most effort but you should definitely learn to use this route as soon as possible as it makes writing async code a lot easier (plus you'll avoid getting a bunch of nasty nested then statement). You could try out using option 1 and 2 just to get a feel for how the flow of the express code works.
I tried to get a document using document.findOne() but it's value is showing undefined .
Here is my code
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
const user= Student.findOne({srno:req.body.srno});
console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
I'm implementing session authentication using express-session. Here when I log the user it's showing schema and bunch of other stuff which I don't know(The error is too long) . user.srno is also showing as undefined. How can I fix it?
I tried using call-back function which gave me required document correctly. But I want the query to return the correct document and store it in user.
Using callback function
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
Student.findOne({srno:req.body.srno},(err,result)=>
{
console.log(result);
});
//console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
You need to wait the result from your query on the database before doing the next task like comparing your password, and looks like you just try to log in, you re not going to register a new one, so it's better to use the compare method in Bcrypt like this :
app.post("/studentlogin", async (req , res) => {
const {srno, password} = req.body // destructuring your request is better for visibility
try {
const user = await Student.findOne({srno: srno});//await the result before next step
console.log(user.srno) //you can check
if(!user) {
console.log("invalid user");
// your logic to tell not student found /wrong username or password, and/or redirect
}
const isMatch = await bcrypt.compare(password, user.password) //await the result and this method for comparing the request password and the user's password found
if(!isMatch) {
//your code to tell Wrong username or password
res.redirect("/studentlogin");
} else {
// your code to access to the login.
res.redirect("/");
}
} catch (err) {
console.log(err)
}
The error you are facing is because you are not using async await in your code. use async in your function definition then use await where you are searching the database.
const someFunction = async(req,res)=>{
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
Your code should look like this.
app.post("/studentlogin", async(req,res)=> {
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
console.log(user) to verify.
Hope it helps.
I'm trying to implement login method where I'm searing the user by his/her email then checking for the password verification.
So, if the email is invalid then throwing an invalid email response and with password, I'm doing the same, but the bycrpt.compare gives me a false when I compare the candidatePassword and the user stored Password. I have checked the password from the database(MongoDB) too, it is correct also tried printing the password and the hashedPassword to the console to see I'm getting the data and it does prints. So, came to a conclusion that there is some error with the bcrypt.compare method.
Can you guys please help me if I'm hashing it wrong or my method for checking the password is wrong?
Any help is appreciated.
User_model:
userSchema.methods.correctPassword = async (candidatePassword, userPassword) => {
console.log(candidatePassword, "user=>", userPassword)
return await bcrypt.compare(candidatePassword, userPassword);
};
export const user = mongoose.model('user', userSchema);
Login-File:
export const loginUser = async (req, res, next) => {
try {
const { email, passcode } = req.body;
// 1) Check if email and password is empty
if (!email || !passcode)
return res.status(400).send('Please provide email and password!');
// 2) Check if user exists && password is correct
const user = await UserModule.findOne({ email }).select('+passcode');
console.log("user=>", passcode, "\n", "hashed=>", user.passcode, "\n", await user.correctPassword(passcode, user.passcode))
if (!user || !(await user.correctPassword(passcode, user.passcode)))
return res.send("Email or Password is invalid.")
res.send(message: "Logged in Successfully");
}
catch (err) {
res.send(err.message)
}
}
Output
user=> vandor1passcode
hashed=> $2b$12$LdpTufKRc2qXiWh2YOfNUO9f4QnNI/jfT4Hq9/.GJ2O7cTWjFugoy
false
So, I found an answer to this problem.
Basically, my hashed password was getting hashed properly with a salt of size 12, and when I was comparing it to my existing stored password it was comparing with size salt of 10. That was the problem why I was getting false in result even though my password was correct.
I am trying to get data from data base for a certain creator or user, but it shows data even if the creator doesn't exists.
this is the code
app.use('/api/places', placesRoutes);
router.get('/user/:uid', placesControllers.getPlacesByUserId);
const getPlacesByUserId = async(req, res, next) => {
console.log("request data!", req.params.uid);
const userId = req.params.uid;
let places;
try {
places = await Place.find({ creater: userId });
} catch (err) {
const error = new HttpError('Something went wrong, could not find a place for the given user.',500);
return next(error);
}
if(!places || places.length === 0){
return next(new HttpError('Could not find a place for the provided userid.',404));
}
res.json({ places: places.map( place => place.toObject({ getters: true }) ) });
};
this the data entry saved in mondo db
{"_id":{"$oid":"62ab10baa6f33b1c588dfb8e"},"title":"ifel tower","description":"big tower","image":"https://pixabay.com/images/search/nature/","address":"Circular Rd, Walled City of Lahore, Lahore, Punjab 54000, Pakistan","location":{"lat":{"$numberDouble":"31.5924979"},"lng":{"$numberDouble":"74.3073198"}},"creator":"u1","__v":{"$numberInt":"0"}}
it should only show data on this url
api/places/user/u1
but it show the same data on different creator id's
data with different url
I think it's related to the typo in the following line:
places = await Place.find({ creater: userId });
I guess creater should be creator instead.
I just started a project where I have to use Node + few things related to it and I feel a little confused!
I use JWT for authentication, particularly I created my project like this:
api
|---teams
|----teams.controller.js
|----teams.router.js
|----teams.service.js
|---users (same as team)
auth
|---token_validation.js
other things
|---other things
I use token_validation.js for JWT to validate user while login and seems it work (verified with Postman)
const jwt = require("jsonwebtoken");
module.exports = {
checkToken: (req, res, next) => {
let token = req.get("authorization");
if (token) {
// Remove Bearer from string
token = token.slice(7);
jwt.verify(token, process.env.JWT_KEY, (err, decoded) => {
if (err) {
console.log("err: " + err);
return res.json({
success: 0,
message: "Invalid Token..."
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// other code
}
}
};
I need to insert a new team in DB (MariaDB) and user can create a new team after login. My problem is that while using Session in Java for e.g. I can easly set extras like username of the logged in user and when I need to know what's the username of the logged in user is, I can take it from session
String username = (String) session.getAttribute("username");
I can't understand how to do the same with Node/JWT. What I need to do is, after login I need to save the user_id and when user crate a new team I need to send to DB the user_id with other data (if token still valid).
const {
create
} = require("./teams.service");
module.exports = {
createTeam: (req, res) => {
const body = req.body;
// here I need to check if token still valid
// if yes -> take user id and send it to DB with
// other data
create(body, (err, results) => {
if (err) { // if fails
// handle
}
return res.status(200).json({ // success
success: 1,
data: results
});
});
},
}
I thought I could add it in user.controller.js when user login:
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h",
user_id: get somehow //error
});
// other code
}
but it gives me an error, tells me like I can't add user_id to sign. Can anyone please tell me the right way to store and get this kind of data and use them when needed while user still have a valid token to stay logged in?
You are adding your data to the options, not the payload.
if (result) {
results.password = undefined;
results.user_id = XXXXXXXX //get somehow
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
...
}
Best option is to set it in localStorage. When you make a req to backend send it with headers, then in backend check if token is valid and send response with data that you want.