Hello I would like to serve two different front-end applications on same route.
User will send a token in HTTP header and based on the information that token holds application should decide which folder should it serve statically. Is that possible?
I already have a middleware that parses token and provides me with user role.
Preferred behavior would be
module.exports = function (app) {
app.get('/admin' function(req, res) {
if(req.headers.security.role === 1) {
// serve superadmin page
} else if(req.headers.security.role === 2) {
// serve user page
} else {
// serve forbidden page
}
});
};
Of course it is, here is an example with a cookie sent with the request with nodejs.
app.get('*', function (request, response, next) {
let app = request.cookies.app;
if (app) {
response.sendFile(path.resolve(__dirname, 'app.html'))
} else {
response.sendFile(path.resolve(__dirname, 'app2.html'))
}
});
Related
I have html pages which shouldn’t be seen by the users who haven’t logged in. I used the command below and my html pages became public.
app.use(express.static('public'));
For example, I do not want users who are not logged in to see this page.
http://localhost:3000/admin.html
NOTE: what I'm talking about is not a cookie. When you enter the address of the html page in the toolbar, if it is not logged in, it should not be able to reach that page.
Create a custom static middleware, with the middleware you can validate the path(filename for this case).
I will try to explain with comments in a example code:
// path.join here makes it work cross platform with Windows / Linux / etc
var statics = express.static(path.join(__dirname, 'public'));
function secureStatic(pathsToSecure = []) {
return function (req, res, next) {
if (pathsToSecure.length === 0) {
return statics(req, res, next); // Do not secure, forward to static route
}
if (pathsToSecure.indexOf(req.path) > -1) {
return res.status(403).send('<h1>403 Forbidden</h1>'); // Stop request
}
return statics(req, res, next); // forward to static route
};
}
// add public files. List all "private" paths (file)
app.use(secureStatic(['admin.html'])); // instead of app.use(express.static('public'));
But, with this middleware, no one can request to admin.html file via you express server.
I have setup Passport.js using the local-stratagey, with my express server.
When I am logged in and make an async request within NextJS's getInitialProps, it correctly permits the GET request via the client render but not the server side render. That is to say, If I access the private route via the client side routing, it shows the route and permits the aync request, but when I hit the page directly from the browser it permits the route but not the async request via the server side call of getInitialProps.
To add to the complexity, I am using Next.js and it's new api routes. I catch the route in server.js first to authenticate, and then if it's authenticated I pass it on the Next.
// server.js routes
app.get('/apples', function(req, res) {
if (req.isAuthenticated()) {
console.log(`[${req.method}]`, 'SERVER - ROUTE AUTHENTICATED');
return handle(req, res);
} else {
console.log(`[${req.method}]`, 'SERVER - ROUTE NOT AUTHENTICATED');
res.redirect("/login");
}
});
app.get('/api/apples', function(req, res) {
if (req.isAuthenticated()) {
console.log(`[${req.method}]`, 'SERVER - API AUTHENTICATED');
return handle(req, res);
} else {
console.log(`[${req.method}]`, 'SERVER - API NOT AUTHENTICATED');
res.status(401).end();
}
});
// /pages/apples.js - the consuming page
Apples.getInitialProps = async () => {
const response = await fetch('http://localhost:3000/api/apples');
const apples = await response.json();
return { apples }
}
Any help would be much appreciated!
This thread solved my problem: https://spectrum.chat/next-js/general/halp-nextjs-express-passport-next-api-routes~f5f60d4a-cfea-422b-8dfe-ed243b598ce6
The TL;DR is that if you hit the server directly, return the data you want directly from the server, rather than via a subsequent call to the api. The api request should only be used when you hit a page via client side routing.
I have a Express JS code where I load a middleware that defines certain end-points on a router. The endpoints are specific to the user login and logout. I am adding a new authentication in which case I receive my auth token from a different service. When I receive the token from a different service I don't want those end-points to be loaded.
This is my server.js file
let app = express();
const authEndpoints = require('auth'); // this defines router endpoints
const alreadyAuth = require('checkHeaders'); // this middleware checks if request
// already has the auth headers and set res.locals.alreadyAuthenticated to true else false
app.use('/', alreadyAuth);
app.use('/',function(req, res, next) {
if(res.locals.alreadyAuthenticated === false)
next();
else {
console.log('authentication already exists skipping authEndpoints loading');
next('route');
}
}, authEndpoints); // login, logout
//continue here
app.use('/',nextMiddleware);
auth.js file
'use strict';
const express = require('express');
const path = require('path');
const router = express.Router();
router.get('/login', (req, res) => {
// some code
res.sendFile('login.html');
}
router.get('/logout', (req, res) => {
// some code
});
module.exports = router;
I see the console log that prints 'authentication already exists skipping authEndpoints loading' but the endpoints /login and /logout are still accessible.
Also when I comment the whole section
app.use('/',function(req, res, next) {
if(res.locals.alreadyAuthenticated === false)
next();
else {
console.log('authentication already exists skipping authEndpoints loading');
next('route');
}
}, authEndpoints); // login, logout
then the endpoints are not loaded.
Can someone please clarify If this not the way next('route') should be used.
From the top of my head, try adding a isAuthenticated (whatever is your equivalent to this) check to the /login and /logout routes code you listed. if it's authenticated, do a redirect to the protected page, else return the user the login form (or logout thing..). :)
I think that is better if you use the middleware "alreadyAuth" for every request, no matter the route:
app.use(alreadyAuth);
In this way you check the headers in every request for every route. In the "checkHeaders" middleware, you must use an if statement that redirect the user to the login page if is not authenticated, and use next() in the case that is already authenticated.
let checkHeaders = function(req, res, next) {
//some code that check headers
if(isAuthenticate === false) {
res.redirect("/login");
} else {
next();
};
}
Now, all the end points after this middleware are not accessible if the user is not authenticated. So you can use a logout endpoint, or whatever.
Good Luck!
I am creating a user management system - However I am current finding myself checking the user type on a per router bases.
router.get('/admin/settings', (req, res) => {
if(admin) {
//Proceed.
}
}
router.get('/admin/users', (req, res) => {
if(admin) {
//Proceed.
}
}
Is there a better way of doing this? Can't I just set a route like this?
router.get('/admin*', (req, res) => {
if(!admin) {
res.status(404).send('Not found')
}
}
(I have tried and not succeeded, feels like it clashes with other routes)
Also, on a similar note. How Am I supposed to handle denying a user access to a script? Do I send a 404 or 403?
You can use an Express middleware function:
router.use(function(req, res, next) {
if(admin) {
return next();
}
// We fail closed
return res.status(403).send('Forbidden');
});
// This won't get called if the middleware doesn't call next()
router.get('/admin/settings', (req, res) => {
// Do stuff
}
Here, we call next() only if the user is an admin, which allows the call to continue. Any routes added after this middleware will be protected.
Also, on a similar note. How Am I supposed to handle denying a user access to a script?
A 403 is the appropriate code here, though a 404 can also be used if you wish to hide the route from unauthorized clients. I would suggest reading up on what each code is designed for.
Trying to get auth0 working with my electron app. When I follow the default tutorial and try to authenticate with Username-Password-Authentication, the lock fails with a 403 error and responds with "Origin file:// is not allowed".
I've also added "file://*" to the Allowed Origins (CORS) section of my client settings in the auth0 dashboard.
Auth0 Lock with console errors
Origin file:// is not allowed
EDIT:
Lock setup in electron
var lock = new Auth0Lock(
'McQ0ls5GmkJRC1slHwNQ0585MJknnK0L',
'lpsd.auth0.com', {
auth: {
redirect: false,
sso: false
}
});
document.getElementById('pill_login').addEventListener('click', function (e) {
e.preventDefault();
lock.show();
})
I was able to get Auth0 to work by using an internal express server in my electron app to handle serving pages.
First I created a basic express app in a separate folder in my project called http, here will be the express server code and html files to serve.
const path = require('path');
const express = require('express');
const app = express();
app.use(express.static(process.env.P_DIR)); // Serve static files from the Parent Directory (Passed when child proccess is spawned).
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:<PORT>'); // Set this header to allow redirection from localhost to auth0
next();
})
// Default page to serve electron app
app.get('/index', (req, res) => {
res.sendFile(__dirname + '/index.html');
})
// Callback for Auth0
app.get('/auth/callback', (req, res) => {
res.redirect('/index');
})
// Listen on some port
app.listen(<SOME_PORT>, (err) => {
if (err) console.log(err);
console.log('HTTP Server running on ...');
});
Then in the Electron main process, I spawn the express server as a child process
const {spawn} = require('child_process');
const http = spawn('node', ['./dist/http/page-server.js'], {
env: {
P_DIR: __dirname // Pass the current dir to the child process as an env variable, this is for serving static files in the project
}
});
// Log standard output
http.stdout.on('data', (data) => {
console.log(data.toString());
})
// Log errors
http.stderr.on('data', (data) => {
console.log(data.toString());
})
Now the auth0 lock authenticates as expected.