I am trying to restrict all pages if the user is not authenticated.
The strange thing is that my middleware is being called twice when I call the login page.
THe following are my code
app.use((req, res, next) => {
if (req.session.user) {
res.session.user = req.session.user;
}
if (req.isAuthenticated() || req.path === '/' || req.path === '/login'){
console.log('inside next');
next()
}else{
console.log('inside redirect');
res.redirect('/')
}
});
app.get('/', (req, res) => {
console.log('inside /')
res.render('./login', {
css: ['login.css'],
js: ['login.js']
})
});
When I go to localhost:8000/ which is my root page, it prints out following in the console
inside next
inside /
inside redirect
inside next
inside /
As you can see after get('/') is called, the middleware is called once again to redirect the page. Why is this? If I remove the middleware, / gets called only once.
I found out why...
Apparently Chrome recently added a support for source map ESRI : Failed to parse source map
since the source map was not included in my vendor folder, it could not find the source map and refreshed the page.
So from now gotta take caution when copying bootstrap files - copy the source maps with the css file so that it doesn't refresh twice
Related
I try to block access to a Json file by redirecting the user to the home page.
When trying to access to the file I get "can't set header after sent" even if that work.
I don't get this error if I remove app.use(express.static(__dirname));, but I don't know why.
app.get('/', function(req, res){
res.sendFile(__dirname +'/index.html');
});
// Protect file
app.use(function(req, res, next) {
if (req.user == null && req.path === '/File.json')
{
res.redirect('/');
}
next();
});
app.use(express.static(__dirname));
That's because you are trying to set the header after the response res.redirect('/') is sent, express static is trying to set header to a response that's already sent
That is because the next callback It is called event after you the res.redirect
// Protect file
app.use(function(req, res, next) {
if (req.user == null && req.path === '/File.json') {
res.redirect('/');
}
next();
});
As you can see nothing prevent the execution of the next callback. to avoid that you can wrap it inside of a if... else ... statement or you can prepend a return before the res.redirect.
That means even if this condition req.user == null && req.path === '/File.json' is matched. the execution of all the block inside of the IF statement is executed as well as block which are outside the IF statement. So the next callback will be executed which will call the next middleware in the stack which is the express.static and by the way that middleware will try to render the File.json which reset the header after the redirect have been performed.
I've taken this starting pack which I found nice. Everything works fine, but if I refresh when being on a component(e.g. on http://localhost:3000/account-list ) I got 404(since the page doesn't exist.
How should I modify this example to have the index.html page returned?
In fact to have any URL(but the one with a existing file) returing this index.html?
I found the solution(I think); I found the express part on main.js and I replaced the app.get for:
app.use(function (req, res, next) {
if (path.extname(req.path).length > 0) {
// normal static file request
next();
}
else {
// redirect all html requests to `index.html`
res.sendFile(path.resolve(__dirname + '/../dist/index.html'));
}
});
I have this code to load an admin page in Node.js file.
app.get('/admin',function(req,res){
if(req.session.loggedIn == undefined)
{
res.writeHead(301, {
Location: '/login'
});
res.end();
}
else
{
res.send("ADMIN PAGE");
}
});
I will have several pages routed like this, where I check on the session if the user is logged in. If not, I'll redirect to the login page, if the user is logged I show the page.
Can I some how add the restriction to all pages (Except for the login page, of course), without repeating the code, to avoid changing in all routes if in the future, I have to add a new restriction?
Maybe I can use a regex right? but then how can I decide what to do in each rule?
Just create a middleware function and include that wherever you need it. For example:
function requireLoggedIn(req, res, next) {
if (!req.session || req.session.loggedIn === undefined) {
res.writeHead(301, { 'Location': '/login' });
res.end();
return;
}
next();
}
Then just use it in your routes wherever it makes sense, like:
app.get('/admin', requireLoggedIn, function(req, res) {
res.send('ADMIN PAGE');
});
Or you could use it in a separate router, pass it to app.use(), etc.
I have my application structured with 3 Routes (api, admin, default). Each lives in there own file and has it's own middleware and exports a Route. The problem I am facing is when I want to forward to another route that lives on a different router. Essentially I want to call the same function so that I am not serving up the same view from multiple locations.
I don't want to user res.redirect('/someplace') because I want to be able to pass the req and res objects on to the method.
|-app.js
|-routes
|---admin.js
|---api.js
|---default.js
The routes are required and used in app.js as follows
app.use('/api', require('./routes/api')(passport);
app.use('/admin', require('./routes/admin')(passport);
app.use('/', require('./routes/default')(passport);
Inside of admin if have a situation where I need redirect to login and pass some data
// authenticates all routes for the admin router
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.flashMessage.push('Session expired'); //is lost after redirect
res.redirect('/login');
//do I need to restructure my whole app so that I don't
//have to call res.redirect('login')
});
Any ideas on how to structure this? Do I need to export every method and keep all of my routes in one router file? That doesn't very clean, but if the functions are somewhere else it may be too messy.
You can forward it by calling the next callback ,but only if you do not use any paths.
app.use(function(req, res, next) {
// ... api
next();
});
app.use(function(req, res, next) {
// ... admin
next();
});
Another option is use * that will match all paths:
app.use("*", function(req, res, next) {
var path = req.path; // just example how it can be done
if (path === "/api") {
// ...
path = "/admin";
}
if (path === "/admin") {
// ...
}
});
Edit:
I don't think that express has something like next('/login'); ,so basically function that can forward a request to another path and I don't think that is right to have something like this. If a client ask for /admin you should send this particular page and not the page that is under /login. If you want to send back to a client the login page than just redirect it as you did it in your question. I understand that you want to keep the req, res ,but then is the problem in the proposal/structure of your webapp.
With Apache this this really easy, but with Node.JS I don't think so. Simply, I want that when a user click something like this: <a href="/dir/file.png">, he starts to download the file. When I do that, I'm redirected to http://foo.com/fir/file.png, and I visualize the photo. Also say that I have in the app configure this app.use(express.static(__dirname + '/public'));, so, the file is in the public path, and the public path is declared as static. And, when the users click, I dont want that he will be redirected and then the download starts.
I know this is posible, it's just click a link and a download starts! But I don't know how to do it.
Thank's advance!
EDITED:
The HTML where is the <a href="">for the download is here:
app.get('/:user/:id', function (req, res){
usermodel.findOne({ user: req.params.user }, function (err, user){
var imagen = user.imagen.id(req.params.id);
if (err) throw err;
res.render('photo.ejs', {
user: user,
photo: imagen,
});
});
});
Is necessary to create a new app.get? If I do that, I would get redirected? I'm trying to do this without getting redirected.
This depends on the headers you're sending with the image.
To make the browser download the image instead of displaying it, you need to set a "Content-Disposition: attachment" header.
Since you're using the static middleware, this is a bit trickier to do than in your own request handler function. You'll have to inject a middleware before the static one.
app.use(function(req, res, next) {
if (req.path.split('/')[0] === "downloads")
res.attachment(); //short for res.set('Content-Disposition', 'attachment')
next();
});
app.use(express.static(__dirname + '/public'));
Similarly to #rdrey's answer, make the browser download a file if there's ?dl query parameter in the url.
app.use('/gifs/*.gif', function(req, res, next) {
if (req.query.dl !== undefined) res.attachment();
next();
});
app.use('/gifs', express.static(__dirname + '/gifs'));