Using optionally authorized routes with passport and express - express

I would like to make some currently authenticated routes to be optionally authenticated. So that on my routes I could just simply add a public middleware to my router in a following manner:
.get('/projects/:id', public)
My current app.js flow looks like this:
// Authentication
app.use(authRoute);
app.use(defaultRouter);
// request handling
app.all('*', defaultRequestHandler);
So by default all my routes are authenticated, and in my authRoute I do a passport authentication, where I assign the user id to the request.
Using the previous flow, the only way I could think of to make it happen, was to assign an anonymous user id to the request in authRoute if the authentication fails. Also add another middle layer between authRoute and router, which checks from a list if the request url is a public route or not. Is there a simpler way? Thanks!

me im doing it like this:
you have structure like following as example:
-controllers
-helpers
-public
-routes
--index.js
--api
--- index.js
--- subscriber.js
-views
in app.js:
app.use('/', './routes/index');
in directory routes in index.js file
const express = require('express');
const router = express.Router();
router.use(middleware(),require('./api');
router.use(require('./auth');
module.exports = router;
in directory routes/api in index.js file
const express = require('express')
const router = express.Router();
router.use('/subscriber', require('./subscriber'));
module.exports = router;
So every Route which is in directory API is using the auth middleware.
When you add a new rout which needs to be controlled about authentication you can add a new rout in the index.js file in the directory './api/'
Every other route is defined in another folder.

Related

Express router middleware gets called on unexpected routes

Using express, I have multiple routes where I need some middleware. They aren't under any common /url/path.
Router-level middleware says:
Router-level middleware works in the same way as application-level middleware, except it is bound to an instance of express.Router()
As I read it, the implication is that the middleware applies only to the routes of the router instance. But that seems not to be the case.
In the following example, I expect "router called" to be logged only for http://localhost:10000/router.
But it gets logged for http://localhost:10000/noRouter also, which I don't understand. Why does middleware used by the router instance get called for routes that are added to app directly? Is it possible to create a Router so that only routes bound to that Router get the middleware applied?
const express = require('express')
const app = express()
const port = 10000
const router = express.Router();
router.use((req, _res, next) => {
console.log("router called")
next()
})
app.use(router)
router.get('/router', (req, res) => {
res.send("ok")
})
app.get('/noRouter', (req, res) => {
res.send("ok")
})
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
})
P.S.: I'm not stuck and have it working using a different approach. I just want to understand why this doesn't work...
A router is just inserted into a chain of request handlers and is searched/executed in order.
Because you do this:
app.use(router)
You are specifically sending ALL requests to your router. So, all requests will wind through the various handlers in that router looking for one that matches the incoming path. That will include your router.use() middleware which matches ALL paths so it will execute for every URL that gets sent to your router. There is no logic in a router that first checks to see if some route in the router matches before it executes any middleware. A router works just like the app object in this regard and executes middleware in the order it encounters them. So, the only way your middleware doesn't get executed is if the request never gets to the router at all.
If you want middleware to only apply to routes in a router, then you have a couple choices:
Put the router on a common path prefix such as:
app.use("/somerouterprefix", router);
Then, only URLs that get routed to your router will run the middleware in the router. This will, of course, only execute the middleware for routes that start with that prefix, but it will also execute the middleware for routes that start with the prefix, but don't even have a matching route handler in the router. Remember, I said earlier that everything that gets sent to the router will cause your middleware to execute.
Or, secondly, put the middleware on each individual handler in your router so that it will only get executed when it matches some route on your router such as:
const router = express.Router();
// give the middleware a function name so you can
// use it in specific route definitions
function myMiddleware((req, _res, next) => {
console.log("router called")
next()
});
// specify the middleware in your route definition
router.get('/router', myMiddleware, (req, res) => {
res.send("ok")
});

My express router post request is not working on postman

My express router post request is not working on postman , this is my first time using express router on a project ive been stuck on this error and cant seem to find a way to make the post request work
here is my code
my server.js
const express=require('express')
const app=express()
const port=process.env.PORT || 5000
app.get('/',(req,res)=>{
res.json({"msg":"welcome to the server"})
})
//Define Routes
app.use('api/users',require('./routes/users'))
app.use('api/auth', require('./routes/auth'))
app.use('api/contact', require('./routes/contact'))
app.listen(port,()=>console.log(`server is running`))
my users.js
const express=require('express')
const router=express.Router()
//#route POST api/users
//#desc Register a user
//#access Public
router.post('/',(req,res)=>{
res.send('registers a user')
})
module.exports=router;
/ is missing before route prefixes.
Change app.use('api/users',require('./routes/users')) to app.use('/api/users',require('./routes/users'))

routing a request in node.js with express

I have generated a sample app using express generator and inside app.js there is
var routes = require('./routes/index');
var users = require('./routes/users');
There are two files generated index.js and users.js
To use the code inside the files there are this lines
app.use('/', routes);
app.use('/users', users);
My question,is app.use('/', routes) handles every request that is on a route starting with '/', then how will a request to a route to '/users' will be routed to users route
app.use() is middleware. You pass it an optional path and a function and it is the function's job to decide if it wants to pass the request on to further middleware or further routes. It does that by calling next() or if it doesn't want to pass it on, it doesn't call next().
So, if you have:
app.use("/", fn);
That middleware will get called for all paths, but the code inside the function you pass it decides whether to pass the request on or not.

Express: serve static files on subroute

I'm trying to get routing work using Express and create-react-app.
My goal is to address the user to the homepage of the application when the URL is / and to the login page when the URL matches /login.
In my server.js I have two routes defined:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
While apiRoutes contains all the api routing definitions, mainRoutes is responsible for the main navigation (at least this was the idea):
var express = require("express");
var path = require("path");
let router = express.Router();
router.route("/").get((req, res, next) => {
res.sendFile("index.html", { root: "./client/build/" });
});
router.route("/login").get((req, res, next) => {
res.send("This is the login page");
});
module.exports = router;
Somewhere I read about serving the static asset generated by the building process of create-react-app so I added:
// Priority serve any static files.
app.use(express.static(path.join(__dirname, "client/build")));
// All remaining requests return the React app, so it can handle routing.
app.get("*", function(req, res) {
res.sendFile(path.join(__dirname + "/client/build/index.html"));
});
Adding these lines, I successfully see my index.html but I can't visit both /login and /apisubroutes since it redirect me on the main page (index.html) each time.
It's like I need to serve the static files on my subroute mainRoutes but I don't have an idea on how to do that.
How can I make this work?
app.get('*') would match every single route that you have.
You should do something like this:
var mainRoutes = require("./routes/mainRoutes");
var apiRoutes = require("./routes/apiRoutes");
[...]
app.use(express.static(path.join(__dirname, "client/build")));
app.use("/", mainRoutes);
app.use("/api", apiRoutes);
// If the app reaches this point, it means that
// the path did not match any of the ones above
app.use(function(req, res, next){
// redirect the user to where we serve the index.html
res.redirect('/');
});
create-react-app I believe handles routing different, you cannot hook up the browser's route to the route you want to serve because you're running a single page application", unless you do universal routing with server and the js bundle

Why is router.post(..) not see and router.get(...) works fine?

I have a large express app that I have moved to node 7 and transforming the front end using Angular 2.
All seems to be working, except.... the router.post(...) calls.
All the router.get(...) routes work correctly. BUT the router.post(...) routes all respond with 404's.
A sample of the routing is as follows:
<routes.js>
'use strict';
import errors from './components/errors';
import path from 'path';
export default function(app) {
// Insert routes below
app.use('/api/logins', require('./api/login'));
app.use('/api/users', require('./api/user'));
app.use('/api/version', require('./api/version'));
...
app.use('/auth', require('./auth'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get((req, res) => {
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
});
}
and for example for
'use strict';
let express = require('express');
let router = express.Router();
let controller = require('./user.controller');
let auth = require('../../auth/auth.service');
router.post('/', auth.hasRole('admin'), controller.create);
router.get('/', auth.hasRole('admin'), controller.index);
router.get('/clean', auth.hasRole('admin'), controller.cleanDatabase);
router.get('/user/:sharingFromUserId', auth.isAuthenticated(), controller.getUserSharingFromUser);
....
Yet when I do post I see:
POST http://localhost:9000/users/ 404 (Not Found)
One strange hint in Intellij, suggests that the route.post() is not the correct function???? In the editor, the IDE seems to imply that this is the AuthHttp.post() function which is being used in the webpack section of the frontend. How can this be???