How to restrict page access to unlogged users with VueJS? - javascript

I'm currently practicing VueJs and making some sample apps. i'm making a very simple app that is basically just a login page where users will put their credentials and access their profile. However I can't think of a way to restrict view to the profile section if the user isn't logged (i.e that they try to access by manually changing the url to /profile)
The app is pretty barebones, it's just using JS and bootstrap.
Is there a way to immediately redirect users back to the login screen if they're not logged and try to access the profile page?

You can use https://router.vuejs.org/guide/advanced/navigation-guards.html beforeEach to check if the current user is logged or not and do what you need to do :).
your routes:
...
{
path:'/profile',
meta:{guest:false},
component:ProfileComponent
},
...
example :
router.beforeEach((to, from, next) => {
if (!to.meta.guest) {
// check if use already logged
// if true then go to home
return next({path:'/'}); // '/' is home page for example
// else then continue to next()
}
return next();
});

You can use also beforeEnter param if you have only few routes which should be protected.
routes.js
import {ifAuthenticated} from "../middleware/authentication";
{
path: '/test',
name: 'Test',
component: Test,
beforeEnter: ifAuthenticated
},
authentication.js
import store from '../../store'
export const ifAuthenticated = (to, from, next) => {
store.dispatch('User/getUser')
.then(() => {
next()
})
.catch(() => {
next({ name: 'Login', query: { redirect_to: to.fullPath } })
})
}
Example with usage of vuex.

Related

How to Pass a Variable in the vue.js Router "Next" Route

I am using vue.js router in order to re-direct users to the home page (via "next") if they try to access certain pages which require authentication without having a cookie (which is set upon authentication). I would like to pass a variable to the home page within the next route (i.e. next({ name: 'Home' }, variable)), but I am not finding the proper syntax to implement this.
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) {
var cookie = document.cookie
if (cookie === '') {
next({ name: 'Home' })
} else {
next()
}
}
})
Thank you. J

Authentication Middleware for routes not working

I am using Vue, Vuex with Quasar (Quasar might or might not be irrelevant here)
This is my first Application and so I am not sure if I am doing things correctly or not
Below is the code snippet for my routes
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
/*
* If not building with SSR mode, you can
* directly export the Router instantiation
*/
const routes = [
{
path: '/',
component: () => import('layouts/MyLayout.vue'),
beforeEnter: ifAuthenticated ,
children: [
{ path: '', component: () => import('./../container/Index.vue') }
]
}
]
const ifNotAuthenticated = (to, from, next) => {
console.log("here")
if (!store.getters.isAuthenticated) return next()
else next('/')
}
const ifAuthenticated = (to, from, next) => {
if (store.getters.isAuthenticated) return next()
else next('/login')
}
export default function (store) {
const Router = new VueRouter({
mode: 'history',
routes,
// Leave these as is and change from quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
mode: process.env.VUE_ROUTER_MODE,
base: process.env.VUE_ROUTER_BASE
})
return Router
}
Here notice this line of code
const ifNotAuthenticated = (to, from, next) => {
console.log("here")
if (!store.getters.isAuthenticated) return next()
else next('/')
}
With this I was expecting to do client side authentication and based on my understanding/reading about client Authentication
I thought this would be called when I did something like this
beforeEnter: ifAuthenticated ,
But unfortunately that function isn't being called (since it isn't console logging anything).
Any idea of what I might be doing wrong?
You're not calling ifNotAuthenticated anywhere in your code, so you won't see the console log message.
It's probably easier and better to use global beforeEach guard for checking authentication. Here's a very simple example code how you can do it using meta data in your routes config.
I added comments in the code to explain things.
I recommend you to read Navigation Guards in Vue Router documentation.
Also a nice article explaining things more in detail.
const routes = [
{
path: "/dashboard",
name: "Dashboard",
component: () => import("path/to/Dashboard.vue"),
// Add a metadata like this to your private routes
// Tip: If you have a lot of private routes, you can add
// meta: { public: true } to public routes and make
// all other routes private by default.
// In this case you need to change the logic in beforeEach
// below.
meta: { requiresAuth: true },
},
];
export default function(store) {
const Router = new VueRouter({
mode: "history",
routes,
// Other stuff...
});
Router.beforeEach((to, from, next) => {
// See if any of the matched routes has meta "requiresAuth"
if (to.matched.some(route => route.meta.requiresAuth)) {
// Yes this route requires authentication. See if the user is authenticated.
if (store.getters.isAuthenticated) {
// User is authenticated, we allow access.
next();
} else {
// User is not authenticated. We can redirect her to
// our login page. Or wherever we want.
next("/login");
}
} else {
next();
}
});
return Router;
}

How to run js code before everything in the page? I have session check in js and it should redirect to another page

I have session and js checks whether if it exists. It works fine, but dashboard page is seen for miliseconds, like a blink. But I need webpage to redirect before loading html code. How can I do this? I use vue js, even beforeCreate can't help.
Like #Jayem163 said in the notes I would run the authentication verification in your router on beforeRouteEnter Below is a basic example. The router code will run before any render of your component. This way you don't have duplicate code for each route.
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
// no authentication required -- OPTIONAL
const noAuthenticationRequired = (to, from, next) => {
// in my apps right here I force logout. You don't want to go to a login page while logged in. But it's optional
next()
}
// make sure user is authenticated
const requiresAuthentication = (to, from, next) => {
// YOUR CHECK AUTH CODE WOULD GO HERE //
if (success) {
return next()
}
// not successful
next('/login')
}
export default new Router({
routes: [
{
path: '/',
name: 'dashboard',
beforeEnter: requiresAuthentication, // this route will require authentication
component: () => import('./views/Dashboard.vue')
},
{
path: '/login',
name: 'login',
beforeEnter: noAuthenticationRequired,
component: () => import('./views/Login.vue')
},
{
path: '/register',
name: 'register',
beforeEnter: noAuthenticationRequired,
component: () => import('./views/Register.vue')
},
{
path: '/password/forgot',
name: 'forgotPassword',
beforeEnter: noAuthenticationRequired,
component: () => import('./views/ForgotPassword.vue')
}
]
})

Vue Router does not redirect

I am currently trying to only show pages, if the user is logged in. The problem I face is that requireAuth() seems to get called endless amount of times.
The code is use is:
// Routes
const routes = [
{
path: '/',
component: Dashboard,
beforeEnter: (to, from, next) => {
requireAuth(to, from, next);
},
children: [
{
path: '',
name: 'dashboard',
component: DashboardIndex
}, {
path: '*',
name: '404',
component: NotFound
}
]
}, {
path: '/login',
component: Login,
name: 'login',
},
];
function requireAuth (to, from, next) {
if (!localStorage.token) {
console.log('testing');
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
}
// Routing logic
let router = new VueRouter({
routes: routes,
mode: 'hash'
});
testing is output ~1000 times before I receive the error:
[vue-router] uncaught error during route navigation:
warn # app.js
app.js RangeError: Maximum call stack size exceeded
How can I make sure that /login is redirected to if !localStorage.token?
I faced this same issue as the respective error's source all boils down to next() function which is the required to navigate to the path which has to.path as value. If you'll use router.push or router.replace then possibility is to get called endless amount of times as callstack max error displays. So use simply next() and let router API do cumbersome work
I have done this type of thing, but in different manner. I handled all logic in main.js file. and routes.js file contains -
var routes = [{
path:'/login',
component: Login
},
{
path:'/',
component: dashboard
}]
Now I have controlled all type of validation in main.js file using vue-router API as taking help from this - https://router.vuejs.org/en/api/route-object.html
So now main.js would contain -
const checkToken = () => {
if(localStorage.getItem('token') == (null || undefined) ){
console.log('token is not there : ' + localStorage.getItem('token'));
return false;
}
else{
return true
}
}
//then Use `router.push('/login')` as
router.beforeEach((to, from, next) => {
if(to.path == '/') {
if(checkToken()) {
console.log('There is a token, resume. (' + to.path + ')' + 'localstorage token ' + localStorage.getItem("token"));
next();
} else {
console.log('There is no token, redirect to login. (' + to.path + ')');
router.push('/login');
}
}
So you can structure like this as control all the things in main.js and leave route.js outta everything
If you don't have a localStorage token present you are redirecting a user to /login.
Because this is also a a Vue route, your requireAuth logic will run again(because it runs for every route). Meaning you have just created a infinite loop where a user will constantly be redirected to /login even if a user is already on that page.
To stop this simply do not redirect to /login when you already are on /login.
I will leave that part to you but it shouldn't be that hard if you understand what is going on.

Angular Routing and Node Redirect

I am trying to add SAML authentication using passport-saml for my application. I am using Angular for routing. On loading of the homepage, I check for a user through a GET request to my node server "/auth" to check req.user, if it's true, I send back logged in user data; if false, I send back an error message. I have data binding on this user data response so in the event of no user data, I still show "Log in" button.
On click of the "Log in" button, I perform a redirect to the node server "/login". This does passport.authenticate function which runs and then ties in with "/assert" when it's complete to perform a redirect.** It is at this point I am running into a problem.** My redirect always goes to "/" because I am performing a redirect and using angular routing so I dont know how to store this route say "/myPage1" or "/myPage2". NOTE: I do not want to always send back to "/myPage1", I want to be able to "Login" from any view in the SPA.
Am I going about this in the wrong way? Is this a limitation of using Angular routing?
Angular
$scope.login = function () {
window.location.href = 'http://example.com/login';
};
function getCreds() {
$http.get('http://example.com/auth', { withCredentials: true })
.then(function (response) {
$scope.creds = response.data;
});
}
Node.js
app.get('/login', passport.authenticate('saml', { failureRedirect: '/login' }));
app.post("/assert", passport.authenticate('saml', { failureRedirect: '/login' }), function (req, res) {
// console.log('session' + JSON.stringify(req.session));
// console.log("original url " + req.session.originalUrl);
if (req.session.originalUrl) {
res.redirect(req.session.originalUrl);
}
else {
res.redirect('/');
}
});
app.get('/auth', function (req, res) {
var authenticated = req.user;
if (authenticated) {
res.send(req.user);
} else {
res.send({statusCode: 401, message: 'User session is not alive'});
}
});
I have found a way to achieve the desired effect.
Before making the "Login" call, I make another api call to "/setSessionRedirectUrl" which passes the current window.location.href from angular to node server for session storage.
app.post('/setSessionRedirectUrl', function (req, res) {
req.session.samlLoginRedirectUrl = req.body.redirectUrl;
res.send();
});
Then when the assert function is being run after login, it is looking for the req.session.samlLoginRedirectUrl to redirect to. It works!

Categories

Resources