I have a system to upload files with node.js, express and multer, the files are stored inside a static directory. what I want is for them to be stored on the server and be able to see them only if I have logged in.
Issue:
my system to upload is fine, but I need to protect the files in a directory /files/documents/hv.pdf, as the browser saves history whenever I enter the url the file is opened, something that should not happen, how can I avoid access to if the user has not logged in?
I was trying with a Middleware that runs if the url's string bears the name of the / files folder, it's funny that if I do not put the file name or put another name like /files/document/test.txt it works but not When I visited the link in the static folder, I thought it was the cache but it's definitely not that
this Middleware
module.exports = (req,res,next)=>{
let regex = /^\/files\/.*$/;
if (!regex.test(req.url)) { return next(); }
// for test
req.session.user = {name:"thaylor"}; //comment for not session
//fin for test
if(req.session.user){
next();
}else{
res.end('You are not allowed!');
}
}
Middleware for get root path and protected route app.js
const protectedfile = require("./controllers/protectedfile");
app.use(function(req, res, next) {
req.rootPath = __dirname;
next();
});
app.use('/files', protectedfile);
app.use('/files', express.static(path.join(__dirname, 'files')) );
this file controllers/protectedfile.js
const path = require('path');
module.exports = (req,res,next)=>{
if(!req.session.user){
res.send("Route protected");
}else{
let file = path.join(req.rootPath, req.originalUrl);
res.download(file, function (err) {
if (err) {
console.log("Error");
console.log(err);
} else {
console.log("success");
}
});
}
}
Before I'm going to diving into details, one thing to keep in mind is everything in Express.js framework is treated as a piece of middleware. So your oder of code is important (i.e. how your app.use
is wired in order). Each time a client access your application would go from the top of your app.js
file until something could be returned.
First, a static route means the the content deliver through this given path (folder) is static. Typically, in the top head of app.js
file, there is:
app.use(express.static('./public', options));
In the above code, folder 'public' is set to be static. That is anything put into this folder (including the document put into its subfolder) is totally transparent to the public, so that you don't need to specify what have been put into this folder. When a client try to make a HTTP request to your server, Express will scan through the folder and return the document once the requested file could be found; if not, then it go through your next app.use
.
And you can assign multiple static routes. For example, if you now attached the following code after the above code:
app.use(express.static('./file', options));
Your server will now scan the folder named after 'file' after nothing was found in './public' path, and try to find out the requested document. Basically, do the same thing as above.
Here is the trick you can play by replacing the above code as this:
app.use('/file', checkIfTheUserHaveLogIn);
app.use('/file', express.static('./file', options));
or in one line:
app.use('/file', checkIfTheUserHaveLogIn, express.static('./file', options));
Here, I use '/file'
as the first argument in app.use
to specify a special path in the URL that have to be matched. Note, the checkIfTheUserHaveLogIn
is a middleware function which serve as controller(function) to decide if allow the client to access the next level of the middleware (by calling next()
), which is express.static('./file', options)
. You can redirect the client to login page or do something else in the checkIfTheUserHaveLogIn
if the client have not been granted with that privilege.
In your code, you set a router to screen out the '/file' routing path to perform your authentication. However, because how the order of your middleware matters. It is actually trigger the static router first, and the document can be found, so that the file have been already returned to the requested client. Your middleware is actually never been reached. To avoid it, simply just follow what I was did before, setting another static route and point to a another folder (must not be a subfolder under the first transparent static router, i.e. not under ./public
as in my example). Then it should works perfectly.
Hope my explanation clarify your question.
var express = require("express");
var path = require( "path" );
var app = express();
app.use( '/upload', isLoggedIn, express.static( path.join( __dirname, '**your upload folder name**' ) ) );
app.listen( 3000 );
//Use this code if you are using passport.js for authentication mech.
function isLoggedIn(req, res, next) {
if (req.user) {
next();
} else {
res.redirect('/login');
}
}
//Use this code for custom sign in implementation
function isLoggedIn(req, res, next) {
//check if user is logged in
// your business logic goes here
if ( condition ) {
next();
} else {
res.redirect('/login');
}
}
By doing this every time you call localhost:3000/upload/* will via isLoggedIn function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With