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.
Related
I currently have a service authentication up and running (using jwt to auth).
I'm working on a quiz service that force user to create some required information and force them to take a quiz to understand how to use our tool.
Because lacking of Frontend exp, I'm wondering how this quiz service will integrate with the auth service
Right now, for Backend side during auth service I will give them back the permission in the token if I call the function to check if the user pass the test & have a profile created. Otherwise I give them back the token with permission = []
But for the Frontend side, what is the solution to re-direct use to Quiz page (after sign-in and what about user that already log-in before)
check this documentation programatic navigation
once authenticated redirect the user back using [vue2 code]
this.$router.push({name:'Quiz',params:{id:this.$route.query.next})
In the authentication page you may pass the quiz link as next query parameter eg
example.com/login?next=< quizID >
Navigation guard documentation
You can use route guards to redirect unauthenticated users to the login page, do remember to pass the quiz id as a query parameter.
your guard will be similar to this
router.beforeEach((to, from, next) => {
if (to.name === 'Quiz' && !isAuthenticated) next({ name: 'Login', query: { next: to.params.quizID }})
else next()
})
This was assuming you have set your routes has a route named Quiz and takes :id and a route named login, similar to this.
{
path: '/quiz/:id',
name: 'Quiz',
.....
},
{
path: '/login',
name: 'Login',
......
},
Alternatively, you could have set up a dialog box on the quiz page that handles authication.
In Vue, when I want to restrict some pages for some users, in router I define a permission in meta, like this:
routes: [
{
path: 'transport',
name: 'transport',
component: Transport,
meta: { permission: "edit_transport" }
},
]
When user logins I have its JWT where I can find what permission he/she has and in route.beforeEach, I check if user has this permission, he/she can visit a page.
router.beforeEach((to, from, next) => {
let token = window.localStorage.getItem('user_token');
if(to.meta.permission == 'edit_transport') {
//if user's token has edit_tranport permission let him visit the page
}
})
But, now I have this permissions In database, there is a table where admin defines permission for page:
id permision page
_____________________________________
1 edit_transport transport
2 write_post create_post
This means, for example user needs edit_transport permission to visit transport page.
My solution is: first I have to take all this permissions from database and save them in vuex store, and then access this store data in route.beforeEach and check what permission page needs and then check if user has this permission
router.beforeEach((to, from, next) => {
let token = window.localStorage.getItem('user_token');
let pagepermission = store.permissions[to.name]
if (token.has(pagepermission)) {
// let user visit the page
} else {
// redirect
}
})
So, is it a good way or is there any other way better then this?
This is a good check to do on the client side, if you are also protecting routes / endpoints on the back end I think that would be the most well rounded solution.
I'm not sure what you're using on the backend but if its Node, you could use something like Passport to manage roles - as a middleware to routes and endpoints.
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.
I have a web app where users can log in.
After users log in, they are authenticated by using Express and Passport.
The code after successfully authenticating users is as the following.
router.get("/", function(req, res) {
res.render("index", { user: req.user });
});
Now, user's data is stored in user, so if I want to render user's email on the index page, I can do it by user.email. There is no problem so far.
I use React.js as my choice of Javascript library, and the problem arises here.
Let's say that I want to show user's email through React.js on the index page after they logged in, so my code ended up like the following.
var HelloMessage = React.createClass({
render: function() {
return (
<p>
Your current email is {this.props.email}.
</p>
);
}
});
ReactDOM.render(<HelloMessage email={user.email} />, document.getElementById('hello'));
My intention here is that I can retrieve user's email the same way I retrieve on index page without React.js. So, I put user.email as my prop for email, but this clearly didn't work. It ended up returning error message saying Uncaught ReferenceError: user is not defined. Does anyone know how to retrieve data for the email using React.js?
I am logging in the system successfully but
I want that the user whose role is 'Administrator' can only go to all the routes and user having role as 'Manager' can go to 'Home' and 'GetDocumentDetails' else the other login users will be restricted to home page and the guest to Login page.
My route and filter files are as follows:
Routes:
Route::post('/login', function()
{
$user = array(
'username' => Input::get('username'),
'password' => Input::get('password'));
// verify user credentials
if (Auth::attempt($user,true))
{
$role= Auth::user()->userrole;
return Redirect::route('home');
}
}
// Route for getting document details using get method
Route::get('GetDocumentDetailsById',array('as'=>'GetDocumentDetailsById','uses'=>'DocumentController#GetDocumentDetailsById'));
// Route for guest user
Route::filter('guest', function()
{
if (Auth::check())
return Redirect::route('home')->with('flash_notice', 'You are already logged in!');
// Redirect Log-in user to his home page
});
Filters:
/* Filter to redirect guest user to login page */
Route::filter('auth', function()
{
$role=Auth::user();
if (Auth::guest()) return Redirect::guest('login');
});
Route::filter('auth.basic', function()
{
return Auth::basic('username');
});
Route::filter('guest', function()
{
if (Auth::check()) return Redirect::to('/');
});
I would recommend using Zizaco's Entrust and Confide packages for this purpose, as they greatly simplify this task.
Follow the tutorials on these pages after installing both packages, and then you can limit access to certain routes just by defining Route Permission filters or regular Route filters. No need for any additional logic in controller actions.
These Route Permission filters can easily be defined like this:
// Any route under admin is only accessible by users with role Admin.
// Redirect happens if user doesn't have this role.
Entrust::routeNeedsRole('admin*', 'Admin', Redirect::to('/'));
A Route filter based on permissions would look like this:
Route::filter('myFilter', function()
{
if (!Entrust::can('get_document_details') )
{
return Redirect::to('/');
}
});
This filter could then be applied to any route. See the Entrust documentation for more examples and features. Entrust is really versatile.