NodeJS Express Angular protect Frontend by middleware - node.js

I have a NodeJS Backend running, which uses the express framework.
In the frontend I use Angular. In the past I build two Docker Containers (one frontend, one backend). Now I want to build just one container, in which NodeJS run as usual. But it should also provide my frontend. It is working, so here is my code:
import express = require("express");
import session = require('express-session');
import dotenv from 'dotenv';
dotenv.config();
const app = express();
const port = process.env.PORT || 80;
...
const isOnline: RequestHandler = (req: express.Request, res: express.Response, next: express.NextFunction) => {
if (!req.session.user) {
return res.redirect('/auth/login?rd=' + req.originalUrl);
}
next();
};
...
app.use('/api', isOnline, apiRoutes);
app.use('/auth', authRoutes);
app.get('*.*', express.static(path.join('./', 'dist'), {maxAge: '1y'}));
app.get('*', isOnline, (req: express.Request, res: express.Response) => {
res.status(200).sendFile(`/`, {root: path.join('./', 'dist')});
});
app.listen(port, () => console.log('API running on port ' + port));
Code explaination
So actually there are three types of routes. The API, the Authorization and the Frontend paths. The API and the Frontend should be only accessible by users which are authorized. The Authorization is available for everyone.
Issue / Question
The issue is, that I provide all files from the dist folder (in which my build angular app is located), which has a dot (so all file names).
And when I open the app (example.com), I will directly redirect to the auth route. This means the middleware is working. But if add the index file to the path (example.com/index.html), I have access to the app directly, because it is provided by the . route.
Solution Ideas
Is there maybe any way to exclude the index.html from the wildcard statement (or do I stop providing angular by this)?
Can I catch the route exmpla.com/index.html and redirect to the base path?
Or is there any other way to protect my whole angular app by my middleware?

you might completely close public (dist) folder:
app.get('*.*', isOnline, express.static(path.join('./', 'dist'), {maxAge: '1y'}));
leaving publicly open only api and login route
and on the login route in authRoutes, render a login page with some minimal inlined css and form or javascript to handle the login:
authRoutes.get('login', /*res.sendFile with styles and login form*/)
authRoutes.post('login', /*handle login*/)
//...

Related

express route and react route have conflict - it is returning api result on heroku

first of all it's working proper in my local but it works the way i don't want on heroku.
I working on a MERN stack app and I have express path same time react router path.
https://test.herokuapp.com/project
in my node.js express side
server.js
--------
/* Router */
import routes from "./routes/index.js"
app.use('/', routes)
/* For Deployment */
if(process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, './../client/build')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, "../client/build/index.html"));
})
}
routes/index.js (it returns project data from mongodb)
---------------
router.get( '/project', ProjectController.getAll);
at the same time i have a another route in my react side
const routers = (isUserAuth, isAdminAuth) => [
{
path: '/project',
exact: true,
element: <Project />
}
]
http://localhost:3000/project
that route when react router redirect with a NavLink working and if page refresh manually still working in my local. But when it comes to heroku platform it's working redirect with NavLink but it doesn't work when refresh the page. When refresh the page as i said it returns project data from express serve nodejs side.
I think it's about the first code block I put above. thanks..

Run a function inside Express route and still render page in sendFile

I have a React app using server-side rendering and I'm trying to hit a route using middleware to check assign redirects.
const app = express();
...
app.use("/", redirectRouter);
app.use("/widgets", widgetRouter);
app.use("/api", apiRouter);
app.use((req: Request, res: Response) => {
res.sendFile(path.join(__dirname, "public", "index.html"));
});
The second two middlewares are for some backend purposes and the last app.use serves up the React app if no other route is found. app.use("/", redirectRouter) is where I'm trying to run a loop that assigns redirects to an array of URLs. I want express to hit the middleware, run, but still serve index.html at the bottom.
Currently app.use("/", redirectRouter) does nothing. I've tried changing "/" to "*" which hits the route but no longer renders the page. I've also tried variations of app.get, app.all, and app.options which also do nothing.
EDIT: Forgot to add that this is inside the redirectRouter
redirectRouter.get("*", async (req: Request, res: Response) => {
// my function
});
But the problems are the same... "*" hangs up the app and "/" does nothing.

Webpack proxy messing up my routing?

So I'm using webpack for a project on 8080 with a backend on 3000. The proxy seems to work fine, as I can send requests to the backend and access it without issue. However. I need to include this middleware that allows me to have a user load the page, and if they've logged in within a certain amount of time, the initial request they send to the server logs them in automatically.
router.use(function (req, res, next) {
//check token for routes beneath vvvv
})
router.post('/preauth', function (req, res) {
//return user account info if req.token is valid
})
When I try to get to prauth, or even any route before that from the page loaded on 8080 I only touch the middleware and nothing else.
When I do npm run build then try it again from the identical page on 3000, it works as expected.
No, CORS is not enabled and the proxy does not rewrite any url.
Does anyone know if something in my Webpack config might be causing this?
You need install Cors in nodejs:npm install cors, you can try the following below or you see: Nodejs + Vuejs
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('This is a CORS-enabled web server listening on port 80')
})

Prevent Angular 6 router from overriding routes defined in Express Server

How do I prevent Angular routing from interferring with routes from an Express Node Server?
I'm setting up some routes ( to node-RED middleware) in my Express server:
server.js
// Serve the editor UI from /red
app.use(settings.httpAdminRoot,RED.httpAdmin);
// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot,RED.httpNode);
// Angular DIST output folder
app.use(express.static(path.join(__dirname, 'dist')));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});
but in my router module they get always overridden ( with our without the default path redirection)
routing.module.ts
const appRoutes: Routes = [
{
path: "example-page",
loadChildren: "../modules/example/example.module#ExampleModule?sync=true"
},
// Last routing path specifies default path for application entry
/* {
path: "**",
redirectTo: "/example-page",
pathMatch: "full"
},*/
];
I'm only providing this little code because I want to ask in general how do I prevent Angular from interferring with routes defined in an Express server and what is the best practice for routing in an Express/ Node.js + Angular + AspNetCore + Webpack app.
If you're using Angular, then let Angular handle all pages. This code takes care of that and hence angular is handling all routes.
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});
If you want express to handle some routes instead of angular, handle that route before handling angular route as follows:
app.get('/some-non-angular-path', (req, res) => {
//code to handle this path. once it is handled here, angular won't be involved
//non-angular-paths should come first in the order
});
app.get((req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.js'));
});

Express SSL redirect not working for root /

I use a wildcard match at the end of my Express route declarations to test if the connection is not HTTPS and if not, to redirect to the HTTPS version of the URI.
This works for everything except root, i.e., www.domain.com. This is a bit of a problem because domain.com serves a SPA.
app.get('*', function (req, res) {
if (req.headers['X-forwarded-proto'] != 'https') {
res.redirect('https://domain.com/#' + url_path);
}
else {
res.redirect('/#' + url_path);
}
});
I noticed that this chunk of code does not even get called when the URL is the root domain. I think this might be because I also declare:
app.use(express.static(path.join(application_root, 'public')));
This is necessary for the SPA to serve all of the assets. When I remove this line, my route handler is now called for the root domain, but my home page now infinitely redirects.
I had to create a custom route to server my SPA file, rename index.html so that Express would not try to serve it instead of my route.
To anyone who might still be struggeling with this, I had the same problem deploying my React-Express App on Heroku. I used a middleware: "heroku-ssl-redirect". The solution for me was to put this middleware up in the hierarchy (now its the first middleware I am applying):
var sslRedirect = require("heroku-ssl-redirect");
const express = require('express');
const path = require('path');
const e = require('express');
const app = express();
app.use(sslRedirect());
// Serve the static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));
// Handles any requests that don't match the ones above
app.get('*', (req, res) =>{
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
const port = process.env.PORT || 5000;
app.listen(port);
console.log('App is listening on port ' + port);

Resources