I want to find the logged in user, and set their info to app.locals so that I can use it in any view.
I'm setting it up in my server.js file like so:
app.use(ensureAuthenticated, function(req, res, next) {
User.findOne({ _id: req.session.passport.user }, (err, user) => {
console.log('user\n', user)
app.locals.logged_in_user = user;
next();
})
});
console.log('user\n', user) confirms that the user has been found.
Then, I should be able to use this user's info in any partial, such as in my layout.hbs file like so:
Currently, {{logged_in_user}} is logged in.
But, it's not working. The answer here suggested to use res.locals instead, but that didn't work. The example here uses static data, but I need dynamic data since user will depend on who's logged in.
Right now, I have to define the user variable in every route. Is there a way to globally define a user variable that can be used in any partial?
You're using passport judging from the code. The documentation states the following:
If authentication succeeds, the next handler will be invoked and the req.user property will be set to the authenticated user.
Therefore you can do the following (or however you want to do it):
app.use((req, res, next) => {
res.locals.user = req.user
next()
}
This will pass the user object to all requests and the views.
Related
I'm using Passport-jwt with Express. I'd liket to restrict pages from logged-in user by middle-ware.
For example, I have a page, /dear-not-sign-in-user After a user logged-in, the user can't access the page. So basically I'd like to implement the opposite of passport.authenticate method. How can I detect the user's token is not valid?
router.get(
"/dear-not-sign-in-user",
!passport.authenticate("jwt", { session: false }),
(req, res) => {
console.log('this user is not logged-in yet');
}
);
Above code doesn't work, but you get the idea what I want to do.
I have some routes protected in vue-router, this I do through the meta property of the routes in vue-router.
When I load the index route, that is, all the records show me the edit button since at that moment I have this permission, if I update that user, I go to another panel with the admin user and I remove said permission. Now I go to the normal user and I give in the edit button of my table, I should send me to a route 403 since I do not have that permission at that moment, but it does not, just to the next navigation to another route I update the permissions. How do I solve this?
router.beforeEach((to, from, next) => {
store.dispatch('ME'); // get permissions before navigate route
if (to.matched.some(record => record.meta.permission_name)) {
// I check if the route permits, otherwise send to route 403
if(!store.getters.containsPermission(to.meta.permission_name)){
next({name : '403'})
}
else{
next()
}
}
else{
next()
}
})
The permissions are in the database from the backend I use Laravel and Laravel Permissions, by modifying the permissions for that user from another administrator user, and doing the store.dispatch('ME'); I get the new permissions, which I thought that by calling the dispatch before evaluating the meta, it would arrive correctly to the next({'403'});
I hope you understand me, if not, do not hesitate to comment.
Don't put permissions in your store. I, or someone else like me who is crafty, could just insert full permissions for your application whenever I wanted. Instead, query with the API for them before every route change.
router.beforeEach(async (to, from, next) => {
try {
await api.get('permissions', { params: permissions: to.matched.some((record) => record.meta.permission_name }})
next()
} catch (e) {
next({ name: '403 })
}
})
And just handle it server side.
Supposing we have some middleware in express 4.0:
app.use((req, res, next) => {
// ... i want app here. except this
// method is imported from another file
// so app isn't in scope.
});
Is there any way to get the app object?
I'm writing several custom middleware packages and I keep finding myself needing to reference app (from another file of course). I'm doing hokey things like this:
app.use(fabMiddleware(app));
Which is really a high-order function:
const fabMiddleware = (app) => {
return function(req, res, next) {
// ... now i can use app
}
}
modue.exports = fabMiddleware;
Does perhaps this, req or res have a reference to app?
Yes you can access the app instance without needing to explicitly pass it in. Simply call req.app or res.app to get access to it.
https://expressjs.com/en/4x/api.html#req.app
https://expressjs.com/en/4x/api.html#res.app
I'm using a expressjs 4.x to build a simple api on top of mongodb.
The api needs to serve a few sets of data:
/api/v1/datatype1
/api/v1/datatype2
For each data type, I have CRUD operations (post, get, put, delete).
The api requests would look like this:
POST /api/v1/datatype1
GET /api/v1/datatype1:_id
PUT /api/v1/datatype1:_id
DELETE /api/v1/datatype1:_id
If I create a router params like this:
dataType1ApiRouter.param("entity_id", function (req, res, next, id) {
//async db fetch here by id, then call next with fetched data
//or error if faild request/not found entity.
//let's say req.dataEntity = dataEtity; next();
} );
If I create a route like this:
dataType1ApiRouter.route("/datatype1")
.get(":entity_id", function (req, res, next) {
//expcet req.dataEntity to be fetched by the param filter.
})
.post(function(req, res, next) {
//just create an new dataType1 entity.
});
I am getting a syntax error. The route .get and .post (and other methods like those) expect just one parameter, resulting in an error:
Route.get() requires callback functions but got a [object String]
Is there a way to actually group all the "/datatype1" requests under one url declaration instead of repeating the method("datatype1:entity_id") for each method that requires the ID expect for the post method?
There isn't a clean way to do this with Router.route(), but you might consider doing this with another Router instead of a Route there. Then, you could just mount that sub-router.
Basic example, modifying the code you provided:
var mainRouter = express.Router(),
subrouter = express.Router();
subrouter.param("entity_id", function (req, res, next, id) {
// param handler attached to subrouter
});
subrouter.post('/', function(req, res, next) {
// post handler attached to base mount-point
});
subrouter.get("/:entity_id", function (req, res, next) {
// get handler attached to base mount-point/<id>
});
// here we mount the sub-router at /datatype1 on the other router
mainRouter.use('/datatype1', subrouter);
Note that this requires adding a '/' to the URL, so instead of /api/v1/datatype1[someidhere] it would be /api/v1/datatype1/someidhere
I'm using node.js with Express and connect-auth to authenticate users.
This is the verification when requesting /index:
if(req.isAuthenticated()) {
res.redirect('/dashboard');
} else {
res.render('index', { layout: 'nonav' });
}
However, after logging out and going back to f.e. '/dashboard', I can see the dashboard.
How can I put the authentication check to every request to make sure there's a valid user at all times?
Update
I don't have any problems with the authentication, everything works fine! I need a solution which checks every route/request if there's a valid user, without putting a function or if-statement in the route-implementation, as the whole App needs a valid user anyway. The Express-Authentication-Example uses "restrict" in the route-definition, which is close, but with many routes it can easily be forgotten.
app.all('*',function(req,res,next){
if(req.isAuthenticated()){
next();
}else{
next(new Error(401)); // 401 Not Authorized
}
});
// NOTE: depending on your version of express,
// you may need to use app.error here, rather
// than app.use.
app.use(function(err,req,res,next){
// Just basic, should be filled out to next()
// or respond on all possible code paths
if(err instanceof Error){
if(err.message === '401'){
res.render('error401');
}
}
});
If you define the all route before routes which require authentication and after routes which do not (such as the home page, login, etc) then it should only affect the routes that need it. Alternatively you could use a RegExp instead of '*', which would include a subpath or list of paths that require authentication.
Another option would be to create a function to include in each route that requires auth:
function IsAuthenticated(req,res,next){
if(req.isAuthenticated()){
next();
}else{
next(new Error(401));
}
}
app.get('/login',function(req,res,next){
res.render('login');
});
app.get('/dashboard',IsAuthenticated,function(req,res,next){
res.render('dashboard');
});
app.get('/settings',IsAuthenticated,function(req,res,next){
res.render('settings');
});
You can use sessions mechanism provided by connect. Put this code in app.configure() to enable it:
app.use(express.cookieParser());
app.use(express.session({
secret: 'some string used for calculating hash'
}));
After that, you′ll be able to use req.session object (different for each request) to store your authentication data (or anything else). So, your example code will look something like this:
if (req.session && req.session.authorized) {
res.redirect('/dashboard');
}
else {
res.render('index', {layout: 'nonav'});
}
And authentication will look like this:
req.session.authorized = checkPassword(login, passw);
Logout:
req.session.destroy();
More info can be found here.
Another way is to app.use a middleware function. (Example in CoffeeScript.)
# middleware
authKick = (req, res, next) ->
if not do req.isAuthenticated then return res.redirect '/login'
return do next
# apply
app.use authKick
This will work on each request without having to touch the routes.