Auth/Session not working on one page in Sails with Passport - node.js

I have used passport to manage authentication in Sails. It is working bar one odd issue. If I check for a user in order to modify the nav bar
<ul class="nav navbar-nav navbar-right">
{{#if user}}
<li>{{ user.username }}</li>
<li>Logout</li>
User!
{{else}}
<li>Login</li>
{{/if}}
</ul>
The log in and go to / There is nothing there.
When I go to /login or /logout, both of which use the same template and share the code above, I get both conditions being met.
Any ideas?

OK, the issue was that policies in Sails are only applied to Controllers, not views.
Sails Docs
The solution was to create a pages controller, route a method to the home page view and then apply the following policy to it. It passes it by passport but doesn't restrict access.
PageController.js
module.exports = {
home: function (req, res) {
res.view();
}
};
policies.js
'*': ['passport'],
PageController: {
'*': ['passport', true]
}

Related

use href tag for different html pages but with same url id in express

i'm trying to switch between home and profile page for same user with click on each button. also except change between home and profile,id should stay the same.
but after click on profile button only id will be changed and it uses profile as id
(i used ejs as format for my views/html pages)
any idea how can i fix it?is that even possible?
there is my nav code:
<nav>
<div class="nav-wrapper teal darken-4">
BAZAART
<ul class="right hide-on-med-and-down">
<li><a class="waves-effect waves-light btn teal lighten-1" href="home"> <i class="material-icons right">home</i> home</a></li>
<li><a class="waves-effect waves-light btn teal lighten-1" href="profile">profile <i class="material-icons right">account_box</i></a></li>
</ul>
</div>
</nav>
homeController:
exports.sendReqParam = (req, res) => {
let userHome = req.params.userHome;
res.render("home", { name: userHome });
// res.send(`This is the homepage for ${userHome}`);
};
exports.respondWithName = (req, res) => {
let paramsName = req.params.myName;
res.render("profile", { name: paramsName });
}
main.js
app.get("/profile/:myName", homeController.respondWithName);
app.get("/", homeController.respondInfo);
app.get("/home/:userHome", homeController.sendReqParam)
I was recently making a blog website, where I write a post and it displays it on the home page. But if we wanted to go to the specific post page, instead of making another separate page for each new post, we made a post.ejs page instead, and later to acces the specific post we simply used something called lodash. I'll show you an example of it, so it makes more sense, and I'll show you the code we used.
So the example is this, I go to the compose.ejs page and I write a random post: title=Post, content=A random lorem ipsum
and lets say we write another post: title=Another post, content=Another random lorem ipsum
Okay so now everytime we write a blog post it sends us to the home page (where we currently are) and it shows the two blogs posts. If we wanted to go to the specific url of the post, we simply write this link localhost:3000/posts/Another post hit enter and it takes us to the second post we wrote.
And this is the code we used inside the app.js:
app.get("/posts/:postName", function(req, res){
const requestedTitle = _.lowerCase(req.params.postName);
posts.forEach(function(post) {
const storedTitle = _.lowerCase(post.title);
if (storedTitle === requestedTitle) {
res.render("post", {title: post.title, content: post.content});
}
});
});
In the app.js code, we see in the app.get /posts/:postName and this is just the name that is going to show in the url, :postName is like a variable and it will store whatever the user writes.
In the second line, we use lodash to rewrite what the user wrote to what we want, for example if the user wrote AnoTheR POst it will automatically change it to another-post, and we store it in a constant called requestedTitle.
Next is a forEach loop on a posts array (where we store every post), and this is just to go throught every post and check the names.
In the 4th line, we are again using lodash for the same thing, but this time arround for the title of each individual post, and storing it in a constant called storedTitle.
And last, an if statement, where if both the names are the same then it will render the post.ejs page, and we just pass down the title and content from the selected post using this code , {title: post.title, content: post.content}.
And this is the code we used inside the post.ejs:
<%- include("partials/header") -%>
<br>
<div class="card">
<h2 class="card-header"> <%= title %> </h2>
<div class="card-body">
<p class="card-text"> <%= content %> </p>
</div>
</div>
<%- include("partials/footer") -%>
As you can see this post.ejs isn't hard to explain, the top and bottom lines where it says include("partials are just the header and footer templates I use, just to save time coding. Whats inside is what the post.ejs will render when it gets called.
I hope it wasn't that confusing, I'm still learning to code and I hope it helps you with what you are looking for. I think this isn't the exact answer for your question, but I think it will help you navigate your way throught.
If you need more explanation or help, this is my instagram: #cemruniversal, I'm always happy to help if I can.
Edit: 30 minutes after original post
I think I found a way it could work, I'll show you a piece of code from the same blog website.
Whenever I want to compose a new post I use this code:
app.get("/compose", function(req, res){
res.render("compose");
});
And obviously there is a form for you to write the post, and after you submit, it sends you to the home page, and saves the post. For that I used this piece of code:
app.post("/compose", function(req, res){
const post = {
title: req.body.postTitle,
content: req.body.postBody
};
posts.push(post);
res.redirect("/");
});
I had an idea for your website, what if when you pressed the Profile button, it renders a specific page on your site, and when you press another button it renders another page. It could work, wouldn't it?
Please try it out and tell me how it went.
I think something like this:
<nav>
<div class="nav-wrapper teal darken-4">
BAZAART
<ul class="right hide-on-med-and-down">
<li><a class="waves-effect waves-light btn teal lighten-1" href="/home"> <i class="material-icons right">home</i> home</a></li>
<li><a class="waves-effect waves-light btn teal lighten-1" href="/profile">profile <i class="material-icons right">account_box</i></a></li>
</ul>
</div>
</nav>

How do I store a variable for every route in Express.js?

So I'm building a simple authentication application and I'm using express-sessions to do this. For the UI, I need to display in the nav-bar a button for logging in, if the user hasn't done so already, and a button for logging out if they are already logged in.
The problem is, I'm not sure how to store this state across all of my routes, without using the same code for each route. Currently I've got this on the index route, which works fine:
/* GET home page. */
router.get('/', function(req, res, next) {
var logged_in = false;
if (req.session.userId) {
logged_in = true;
}
res.render('general/index', { is_logged_in: logged_in});
});
And in the nav-bar I display the buttons dynamically like so:
<% if( is_logged_in){ %>
<li class="nav-item active">
<a class="nav-link" href="/users/logout">Logout<span class="sr-only">(current)</span></a>
</li>
<% } else { %>
<li class="nav-item active">
<a class="nav-link" href="/login">Login<span class="sr-only">(current)</span></a>
</li>
<% } %>
But the problem is, I have to use the same code for each route if I want this to work for the nav-bar, which goes against DRY coding practices. How do I display this button dynamically without having to repeat the same bit of code on each route, checking if a user session ID exists? Do I set a global variable? I'm new to Express so all help appreciated. Thanks
You can setup a middleware to set the login status and use the res.locals for the lifetime of the request.
function checkLoggedIn(req, res, next) {
var logged_in = false;
if (req.session.userId) {
res.locals.logged_in = true;
}
}
You can then mount it for all the routes or chain it for some routes:
// all routes after this middleware:
app.use(checkLoggedIn)
// chain it
app.get('/mypath', checkLoggedIn, (req, res) => { ... })
res.locals are available to view as well so you can do the following without passing during render.
// You can simply render
res.render('general/index');
// logged_in variable is available to view
<% if(logged_in){ %>

Organizing view files in Node.js app

I finished this walkthrough for creating a very basic Reddit clone using the MEAN stack. The app included a few different views, such as a view for all posts, a single post, the login form, and the register form, and all of these views were included in a single file: views/index.ejs.
Is putting all the views together like this common practice, or was it merely for brevity in the tutorial? I was hoping to be able to separate at least the login and register forms from the rest of the views in index.ejs for the sake of organization, but placing them in a login.ejs file in views causes a 404.
Login portion of views/index.ejs
<script type="text/ng-template" id="/login.html">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-show="error" class="alert alert-danger row">
<span>{{ error.message }}</span>
</div>
<form ng-submit="logIn()"style="margin-top:30px;">
<h3>Log In</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" ng-model="user.username"></input>
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" ng-model="user.password"></input>
</div>
<button type="submit" class="btn btn-primary">Log In</button>
</form>
</script>
Login portion of routes/index.js
router.post('/login', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});
Login portion of controller
.state('login', {
url: '/login',
templateUrl: '/login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'auth', function($state, auth){
if(auth.isLoggedIn()){
$state.go('home');
}
}]
})
I don't understand how the views fit together in this app. What is telling the app to find the login template in index.ejs, and how can I redirect the app to look in a different file?
The way they did this is a little strange, but it was most likely for the sake of brevity.
The reason why it's 404'ing is because of how the routes are set up. There's a single route to serve index.ejs, and the rest of the routing is handled client-side through Angular. In fact, the only reason they used ejs is because they wanted to send it using Express' res.render() method most likely. (Although, since it's just HTML from what I saw, instead of actually using any EJS, they could likely just as easily used Express' res.sendFile() method, or prior to 4.8.0, res.send() in conjunction with Node's builtin fs.readFile to send the plain HTML file.
If you wanted to split out the views you'd have to set up server-side routes, but I guess they were dead set on a single-page app. More commonly, views that are rendered on the server-side are split out into individual files, with a main "layout", in which other views are included into.

Update EJS Layout with Session

My ejs layout provides the current user's username on the main menu through sessions
<a href="">
<% if (typeof currentUser === 'undefined'){%>
<% } else { %>
<a style="text-decoration:none;" href="/users/logout">Logout</a>
<% } %>
</a>
Now when I destroy the session and redirect to the main page, the currentUser's infomation is still showing, although logging currentuser returns undefined. Is there a way to force the layout to update itself to show current information?

Custom Layout for a specific router not displaying in Meteor with Iron Router

I want to use a different layout template for pages such as login, 404, and other pages. However, when calling this template in my route (using Iron Router), it appears to be ignored and instead uses the default template. How can I update this so that it uses the intended layout?
This is the custom layout I want to use
<template name="UtilityLayout">
<div class="ui centered grid">
<div class="six wide column">
{{> yield}}
</div>
</div>
</template>
My general Iron Router Config:
Router.configure({
layoutTemplate: 'AppLayout',
loadingTemplate: 'Loading',
notFoundTemplate: 'NotFoundLayout'
});
This is the before hook where I am calling the route
Router.onBeforeAction(function () {
//redirect to /login if a user is not signed and if they are not already on login (to prevent a redirect loop)
if (!Meteor.userId() && (Router.current().route.getName() !== 'login')) {
this.redirect('login');
// I also tried Router.go('login');
} else {
this.next();
}
});
This is the route where I am referencing the custom layout (that appears to be ignored):
Router.route('/login', { name: 'login'}, function(){
this.layout('UtilityLayout');
});

Resources