I am creating a simple login form that (for now) will log you in as long as the username and password pass the client-side validation function. The form is shown here below (paraphrased a bit).
...
<form id="logonForm">
<input id="email">
<input id="password">
<button type="submit">Logon</button>
</form>
...
It should be noted that this form is being loaded at /login route (have a GET route set up there). On load of the page this form is assigned an onsubmit function as shown below.
...
document.getElementById("logonForm").onsubmit = loginUser;
As a note, loginUser is an imported function from another file. This function has been verified to work though as I am able to step through it when I submit the form. This function does a bunch but the main important parts are depicted below.
...
method = {
method: "POST",
body: loginDetails
};
fetch(url, method)
.then(result => result.json())
.then(result => sessionStorage.setItem("userToken", result[0].userToken))
.catch(error => alert(err.message))
This fetch queries a POST route also located at the /login route with the username and password sent over in FormData() encoding. When I run through this function, no error is thrown by the fetch (or prior/after the fetch) but result returns empty/null.
Investigating this from my server-side code I find that the "POST" route doesn't seem to be actioned even when the fetch is sent. In this following code "That" is never logged to the console but "This" is.
exports.logonUser = (app, formidable, fs, jwt) => {
console.log("This");
app.post('/login', (request, result, next) => {
console.log("That");
...
}
}
This function is called in my server.js file that is run to start the server as shown below.
const home = require('./api/routes/home.js');
const login = require('./api/routes/login.js');
app.use(express.static(path.join(__dirname, process.env.STATIC || 'public/')));
login.openRoute(app, path);
login.logonUser(app, formidable, fs, jwt);
app.use((request, result, next) => {
// This is "true" until I have tokens properly working
if (true) result.redirect('/login');
else next();
});
home.openRoute(app, path);
app.get('/', (request, result) => result.redirect('/home'));
app.listen(process.env.PORT || 3000, () => console.log("[SUCCESS][SERVER] Server is listening on port 3000"));
I have tried re-arranging the functions a bit, but this seems to be the order that gets the functionality as intended (other than the login not working). I have also tried taking out the part that automatically redirects users to /login in-case something funky was happening there, but no luck in that regard either. I am presuming there is something about my server.js code though that cause the POST route on /login to not action. Is there anything that you are able to see that might cause this behaviour? Thank you for all help.
Related
Express js middleware is not working as expected. It is showing too many redirections.
When i remove the token or logout it shows in the browser that too many redirections
Middleware
const isAuthenticate = async (req, res, next) => {
const token = req.cookies.jwt;
if (token) {
jwt.verify(token, "thisisjwtsecret", async (err, token_decode) => {
if (!err) {
const u_id = token_decode._id;
const userData = await User.findOne({ _id: u_id });
req.user = userData;
req.isAuth = true;
next();
} else {
res.redirect("/user/login");
}
});
} else {
res.redirect("/user/login");
}
};
Route.js
// Auth Controller
const AuthController = require("../../controllers/auth/AuthController");
const { isAuthenticate } = require("../../middlewares/isAutheticated");
router.get("/user/login", isAuthenticate, AuthController.login);
router.post("/user/login", AuthController.checkLogin);
router.get("/user/register", isAuthenticate, AuthController.createUser);
router.post("/user/register", isAuthenticate, AuthController.storeUser);
module.exports = router;
LOgin function
// Showing Login Page to User
const login = (req, res) => {
return res.render("auth/login");
};
When i remove the token or logout it shows in the browser that too many redirections
Now that you've shown revised code for isAuthenticate(), the redirect loop is caused by the redirects in that code. Here's what happens:
Some route you have (any route) that uses isAuthenticate as middleware for the route detects that the user is not logged in. It then redirects to /user/login. That's fine up to that point. Then, the browser issues a new request for /user/login and that takes you to this route definition:
router.get("/user/login", isAuthenticate, AuthController.login);
But, that route definition again runs the isAuthenticate() middleware which redirects to /user/login and thus you have an infinite redirect loop.
Probably you just need to remove the isAuthenticate() check from this route. If the user is already going to the /user/login page, you don't need to check their authentication or redirect them. If you have a reason to want to know if they are authenticated or not, then you need a separate version that ONLY does the auth check and does not redirect and you can use that in the /user/login route definition.
Original answer before code was shown that did res.redirect().
So, this middleware you show sets req.isAuth to true or false and then calls next() to continue routing. All three code paths through that middleware just set req.isAuth and then call next(). Nowhere in this middleware does it do any redirect. So, if the core problem is too many redirections, that issue must be caused somewhere else by some other route/middleware that actually does a redirect, probably when it sees that req.isAuth is false since you said that the problem occurs when logged out or when the token is missing.
When redirecting, you have to make absolutely sure that when you redirect to a URL, there is ZERO chance (no code path of any kind) that the route handler for that URL will also redirect to that URL. That's how you get into a redirect loop.
Looking at the other routes you show, if the too many redirects issue is when redirecting to /user/login, then it seems likely the problem is in the authController.login() handler from this route:
router.get("/user/login", isAuthenticate, AuthController.login);
If the code for that route checks req.isAuth and redirects in any circumstances, then that would be an endless redirect loop.
If you need further advice, please provide the following information:
Which exact redirect URL is causing the problem of too many redirects? Is is /user/login?
Show us the code for the route that does that redirect because that's apparently where the fault is.
So I have a mini express app where users can register, login and delete their account. Due html not supporting DELETE I used the npm package methodOverride.
This is what my form and express-override middleware looks like:
server.js
// Method override
app.use(
methodOverride(function (req, res) {
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
let method = req.body._method;
delete req.body._method;
return method;
}
})
index.hbs
<form action="/profile/delete/{{_id}}" method="POST" class="pt-2">
<label for="delete-input_confirmation"></label>
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="btn delete-confirm">Confirm</button>
</form>
Now in my users.js for the delete request:
router.delete('/profile/delete/:id', ensureAuth, async (req, res) => {
try {
let userId = await LocalUser.findById(req.params.id);
if (!userId) {
return res.render('/');
} else {
await LocalUser.findOneAndRemove({ _id: req.params.id });
res.redirect('/register');
console.log(userId);
}
} catch (err) {
console.error(err);
return res.render('/');
}
});
Now what happens with the the code above it goes through fine but it doesn't move past the DELETE request and render the /register page. Then the node server just stops working and I have to restart it and clear my cache. In my mongo db it removes the user so I don't know why this is happening.
I'll put my comments into an answer since this ended up solving it for you.
If you're deleting the current user, but leaving their server-side session open, then that can lead to session issues. To clear that session, you can either call req.session.destroy() or you can remove the session cookie (and the session will become detached from that browser and eventually age away).
The fact that your site becomes non-functional when you have a session of a removed user probably means that you have some error handling problems in your session logic or in accessing the database on behalf of a non-existent user. Your code should be able to field errors when this happens and at least report an error, but probably force the user back to /login.
As the title says, i have a part of my react app that tries to get some data from my database, making a select based on the value I passed to it. So im gonna go ahead and first show the code where i think the problem lies:
So first, this is the function from one of my forms that sends the request to the server, i know code is probably ugly, but i can tell from the console.logs that the parameters im sending are what i intend to send(a string called "licenciaInput"
async handleClickLicencia (event) {
event.preventDefault();
console.log(this.state);
console.log("licenciaInput: "+this.state.licenciaInput);
const datoBuscar = this.state.licenciaInput;
axios.get('http://localhost:3001/atletas/:licencia',this.state)
.then(response =>{
console.log(response)
})
.catch(error =>{
console.log(error)
})
And then, i have this function which is called in that localhost route which attempts to get "licencia", and launch a select in my postgresql db where licencia="whatever", you can see the sentence in the code:
const getAtletasByLicencia = (request, response) => {
const licencia = request.body.licenciaInput;
console.log("Request: "+request);
console.log("what the server gets: "+licencia);
// const licencia = request.licenciaInput;
const sentencia ="SELECT * FROM atleta WHERE licencia ='"+licencia+"'";
pool.query(sentencia, (error, results) =>{
if(error){
throw error
}
response.status(200).json(results.rows)
})
}
As you can see, i have console.logs everywhere, and i still cannot access whatever element i send, because i always get on the server console "undefined" value.
TLDR:How can i access the "licenciaInput" i passed from my client form to my server, i have tried request.body.licenciaInput, request.params.licenciaInput, and request.licenciaInput, but none of those seem to work
I also know i have to treat after that the data i receive from the server, but i need to solve this before looking two steps ahead. Im also really new to React and node/express, so feel free to burn me with good practices im not meeting.Thanks in advance
EDIT: Im also adding this code that i have which shows the route for my method in the server:
app.get('/atletas/:licencia', db.getAtletasByLicencia)
As #Gillespie59 suggested that i should send a POST request, but i dont think i should if im both trying to send a parameter to the server to make a select, and then send the results back to the client
Change your request to:
axios.get(`http://localhost:3001/atletas/${this.state.licenciaInput}`)
...
and your route (if you are using express) should look like this:
app.get('/atletas/:licencia', function (req, res) {
var licencia = req.params.licencia
...
})
As you are using request.body you should send a POST request with axios and add a body.
I have some middleware which uses passport.js, which aims to authenticate a user, then move onto the next piece of middleware:
exports.authenticate = (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
console.log('You are authenticated!!')
next()
})(req, res, next)
}
When the user registers, I see You are authenticated!! in my console. So by this logic, the user should be attached to the req. So I call next and it moves onto this piece of middleware (I want to do something else before the user is redirected):
exports.createMatch = async (req, res) => {
console.log(req.user._id)
}
However, an error on my console and webpage shows TypeError: Cannot read property '_id' of undefined. Why is this and how do I rectify it?
routes.js:
router.post(
'/register',
userController.validateRegistration, // validate them
userController.register, // register them to the db
authController.authenticate, // authenticate them
catchErrors(dataController.createMatch) // do some other bits then redirect
)
Fairly new to Express. If more code is needed let me know. Apologies if something similar was answered elsewhere.
Regards,
James.
This is the line in the source where req.user gets set:
https://github.com/jaredhanson/passport/blob/821a474342b1ae900849911b5c3d3ccc4ef5ab86/lib/http/request.js#L44
It's in the method req.login. The documentation is here:
http://www.passportjs.org/docs/login
It states:
When the login operation completes, user will be assigned to req.user.
Further it says:
passport.authenticate() middleware invokes req.login() automatically.
So far everything sounds like it should work...
However, if you read the section about providing a Custom Callback, which is what you're doing, it states:
Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response.
There are several ways to fix it. You could get rid of the custom callback, you could call login inside the callback, or you could just set req.user = user yourself.
I'm trying to redirect to the home page after a user hit this route: /ref=123 but I want to keep that baseUrl, this is what I have so far:
I am requiring in my server.js file this: const referred = require('./routes/referred').
app.use('/ref=:id', (req, res, next) => {
res.locals = req.params.id
}, referred)
So, when a user hits the above route I am doing some validations in my referred.js file. Actually I need to send some kind of response telling whether that provided id exist or not but showing anyways the home page which is a simple login/resgistration form.
referred.get('/', (req, res, next) => {
//doing validations with res.locals
next() //<- calling the next middleware
})
after calling next() I put that middleware just below to redirect to the home page.
not sure if this is possible: app.use(express.static(_dirname + '/dist')) it seems like is not because I'm getting a 404 .
I know I could use the req.redirect() function but that will actually made a new request to the server and refresh the page erasing the baseUrl that I want to keep up there.
How do you render/send your pages?
You could use res.sendFile('path/to/page.html') to send back any html file while keeping the request URL.
If you want to display a dynamic message on the home page, you should use a viewing engine like ejs. If you are already using an engine, you can do something like
res.render('path/to/page', { status: 'This id does not exist!'})