Auth Filter Not Working - authentication

Trying to use auth filter to keep users from accessing certain routes without being logged in. The code below redirects regardless of the user's status. I was unable to find anywhere what to put within the function. I'm using http://laravel.com/docs/security#protecting-routes for reference. Not sure if I should have an if statement or not. Not sure what to do at all.
Route:
Route::get('/account', ['before' => 'auth', function()
{
// continue to /account
}]);
Standard 'auth' filter from app/filters:
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
//return Redirect::guest('login');
}
}
});
The way I understand it the code within the function should only be loaded if the user is logged in. Otherwise give 401 error.
Thanks for help.

With some help from my friend I fixed it. Some important information, Route filters will continue with intended purpose unless something is returned from filter. Also, the standard auth filter will not work. Must be modified. After that it was cake. Code is below.
Route:
Route::get('/account', ['before' => 'auth', 'uses' => 'SiteController#account']);
Auth Filter:
Route::filter('auth', function()
{
if (Auth::guest())
{
return Response::make('Unauthorized', 401);
}
});

Related

How to get data from $router in Vue

I have to control the status from users that reach my system by an URL created by one QRCode.
Inside my routes.ts, I'm validating if the user is logged and, then, redirecting the user.
if (store.getters.isLogged && to.path === 'QRCode') {
next();
} else {
store.dispatch(AUTH_CHECK).then((token) => {
if (token) {
next();
} else {
Vue.set(router, 'urlQrCode', to.fullPath);
next('/Login');
}
});
}
the prop urlQrCode does not exist on $router by default
When I'm going to '/Login', I can read 'urlQrCode' from $router (In debug mode) but I can't use this.
Which is the best way to resolve this?
My goal is to go to '/Login' and, after the user connect to the system, redirect him to to.fullPath
Solved in Login.Vue by using the following code:
if (!Validator.isNullUndefinedEmpty((<any>this).$router.urlQrCode)) {
this.$router.push((<any>this).$router.urlQrCode);
}

vue-router — Uncaught (in promise) Error: Redirected from "/login" to "/" via a navigation guard

Why is vue-router giving me this error? To be clear, the login flow works as intended but I want to a) get rid of the errro and b) understand why the error is happening.
Error:
Uncaught (in promise) Error: Redirected from "/login" to "/" via a navigation guard.
Login flow
start logged out, but enter a URL that requires auth (i.e. anything besides "/login")
get redirected to "/login" (as expected).
login
successfully get redirected to starting Url from step #1, except with the above error.
Login action:
doLogin({ commit }, loginData) {
commit("loginStart");
axiosClient
.post("/jwt-auth/v1/token", {
username: loginData.username,
password: loginData.password,
})
.then((response) => {
commit("loginStop", null);
commit("setUserData", response.data);
this.categories = airtableQuery.getTable("Categories");
commit("setCategories", this.categories);
this.locations = airtableQuery.getTable("Locations");
commit("setLocations", this.locations);
router.push("/"); // push to site root after authentication
})
.catch((error) => {
console.log(error.response.data.message);
commit("loginStop", error.response.data.message);
commit("delUserData");
});
},
Router:
const routes = [
{
path: "/login",
name: "Login",
component: Login,
meta: { requiresAuth: false },
},
{
path: "/",
name: "Home",
component: Home,
meta: { requiresAuth: true },
},
];
let entryUrl = null;
router.beforeEach((to, from, next) => {
let localStorageUserData = JSON.parse(localStorage.getItem("userData"));
let storeUserData = state.getters.getUserData;
let userData = localStorageUserData || storeUserData;
let isAuthenticated = userData.token !== "" && userData.token !== undefined;
if (to.matched.some((record) => record.meta.requiresAuth)) {
if (!isAuthenticated) {
if (to.name !== "Login" && to.name !== "Home") {
entryUrl = to.fullPath;
}
next({ name: "Login" });
} else if (entryUrl) {
let url = entryUrl;
entryUrl = null;
next(url);
} else {
next();
}
} else {
next();
}
});
I spent hours debugging this and got to the following results for the ugly Uncaught (in promise) Error: Redirected when going from ... Error.
Note that the error is not for the "redirect". It's for the initial caller of the first navigation. Keep reading...
It's by design. Why?
Read this comment.
TL;DR: Let's say you are on page A, and click on a button to take you to page B (kinda like method: goToB() { router.push('/B'); } on page A). But there is a Navigation Guard for page B, that sends you to page C.
This error is a way for letting that goToB() function know that the router hasn't been able to fulfill the desired task, and the user hasn't landed on /B.
It's nasty, but informative
The biggest confusion here is that the redirect (landing on Page C) is, both:
an "expected" outcome to you, the architect of the system. But, at the same time,
an "unexpected" event to the caller of goToB in page A (i.e. router.push), who expects the router to go to page B.
That's why when it's popped as Error, it's confusing and frustrating to "you", who looks at the system entirely and thinks nothing is wrong or erroneous!
Urrrgh... So, what should I do?
Solution 1: Use router-link if you can
I ran into a case that <router-link> was working fine, but router.push was complaining. (I think router-link internally suppresses such errors.)
Solution 2.1: Individual suppress errors on each router.push call
The router.push function is returning a Promise (as it can be considered, or will be, an asynchronous job). All you need to do is to suppress any Error it might throw via
router.push('/B').catch(() => {});
// Add this: ^^^^^^^^^^^^^^^^
Solution 2.2: Augment Router.prototype.push to always suppress errors
If you think you have multiple instances of this, you can augment the push function on the prototype of the Router via the snippet on the same comment to apply this to all the router.push calls on the entire app.
The good news is it's giving you granularity level to choose which error you want to suppress (e.g. only NavigationFailureTypes.redirected ones, for example. The enum is here)
If you are on TypeScript, be my guest on the conversion and typing https://gist.github.com/eyedean/ce6ab6a5108a1bd19ace64382144b5b0 :)
Other tips:
Upgrade your vue-router! Your case might be solved by the time you read this. (As they have a plan to do so, apparently.)
Make sure you are not forking or reaching to dead-end in your Navigation Guards, if you have multiple ones. Follow them one by one and track them step by step. Note that, double redirecting is fine (thanks to this answer), you just need to be double careful!
I also got a playground here: https://codepen.io/eyedean/pen/MWjmKjV You can start mimicking this to your need to figure out where your problem happens in the first place.
The error message is getting updated in the next version of vue-router. The error will read:
Redirected when going from "/login" to "/" via a navigation guard
Somewhere in your code, after being redirected to "/login", you are redirecting back to "/". And vue-router is complaining about. You'll want to make sure you only have one redirect per navigation action.
I had a similar error, but for an onboarding redirect in .beforeEach, which was resolved by replacing in the .beforeEach conditional logic:
next({ name: "Onboarding" });
with
router.push({ path: 'Onboarding' });
This error is meant to inform the caller of $router.push that the navigation didn't go to where it was initially intended. If you expect a redirection you can safely ignore the error with the following code.
import VueRouter from 'vue-router'
const { isNavigationFailure, NavigationFailureType } = VueRouter
...
this.$router.push('/')
.catch((e) => {
if (!isNavigationFailure(e, NavigationFailureType.redirected)) {
Promise.reject(e)
}
}
See https://github.com/vuejs/vue-router/issues/2932 for a discussion regarding this issue.
If your redirect is after a call to router.push('/someroute) then you can catch this error as router.push() is a promise and you can attach a catch to it as below
$router.push('/somesecureroute')
.catch(error => {
console.info(error.message)
})
I have the same error. This error created by router.push("/"); row - it trying to say you that pushing to home was interrupted by redirection in navigation guard.
But actually, it's not an error because it is an expected behaviour.
I made ignoring of such errors by the following way:
const router = new VueRouter({
mode: 'history',
routes: _routes,
});
/**
* Do not throw an exception if push is rejected by redirection from navigation guard
*/
const originalPush = router.push;
router.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) {
return originalPush.call(this, location, onResolve, onReject);
}
return originalPush.call(this, location).catch((err) => {
let reg = new RegExp('^Redirected when going from "[a-z_.\\/]+" to "[a-z_.\\/]+" via a navigation guard.$');
if (reg.test(err.message)) {
// If pushing interrupted because of redirection from navigation guard - ignore it.
return Promise.resolve(false);
}
// Otherwise throw error
return Promise.reject(err);
});
};
I had the same issue, i thought it was config problem but it was not
You can try this code
async doLogin({ commit, dispatch }, loginData) {
commit("loginStart");
let response = await axiosClient
.post("/jwt-auth/v1/token", {
username: loginData.username,
password: loginData.password,
})
return dispacth('attempt', response)
}
async attempt({ commit }, response) {
try {
commit("loginStop", null);
commit("setUserData", response.data);
this.categories = airtableQuery.getTable("Categories");
commit("setCategories", this.categories);
this.locations = airtableQuery.getTable("Locations");
commit("setLocations", this.locations);
}
catch( (error) => {
console.log(error.response.data.message);
commit("loginStop", error.response.data.message);
commit("delUserData");
})
}
And in the component where doLogin action is called
this.doLogin(this.loginData)
.then( () => {
this.$router.replace('/')
.catch( error => {
console.log(error)
})
})
.catch( e => {
console.log(e)
})
It happened to me on application boot, during an authorization check I tried to push to '/auth' but that navigation was cancelled by another call to '/', which occurred just after mine.
So in the end I found that is possible to listen for readiness (https://router.vuejs.org/api/#isready) of vue-router using:
await router.isReady()
or
router.isReady().then(...)
I had the exact same issue triggered by two specific pages, for the two pages that were being redirected due to a login:
if (isAdmin){
router.push({name: 'page'}).catch(error=>{
console.info(error.message)})
else...
otherwise everyone else who is a regular user gets pushed to a different page using "router.push"
ONLY on the redirects that were throwing the original error/warning. Suppressing the warning as suggested in an earlier comment:
if (!to.matched.length) console.warn('no match');
next()
allowed for users to sign in and access pages without proper permissions.
Catching the errors appears to be the way to go, per the suggestion of: kissu

How to Use Multiple Route in ExpressJS?

Is it possible to make router in ExpressJS like this?
users.js
const userController = ('../controllers/userController.js');
router.get('/:userName', userController.paramByUsername);
router.get('/:id', userController.paramByUserId);
In the controller, the code look like this
userController.js
function paramByUsername(req, res) {
User.findOne({
where: {
userId: req.params.userId
}
})
.then((user) => {
if(!user) {
return res.status(404).json({ message: "User not found."});
}
return res.status(200).json(user);
})
.catch((error) => {
return res.status(400).json(error);
});
}
function paramByUserId(req, res) {
User.findByPk(req.params.id)
.then((user) => {
if(!user) {
return res.status(404).json({ message: "User not found."});
}
}).catch((error) => {
return res.status(400).json(error);
});
}
By the code above, what I wanted to achieve is the endpoint like this:
/users/1 this should response same as /users/username.
I have tried the code above, but what I see is an error when I get /users/:id
You can't do both of these together:
router.get('/:userName', userController.paramByUsername);
router.get('/:id', userController.paramByUserId);
From a pure routing point of view, there is no way to tell the difference between these two. Whichever route you declare first will grab everything at the top level and the second will never get hit.
So, in route design, you HAVE to make sure that each route is uniquely recognizable to the Express route matcher based on what you put in the route pattern.
I suppose that if an id was always just numbers and a username could never be just numbers, then you could use a regex route and match only numbers for the id and everything else for the username, but that seems a bit fragile to me and I'd prefer something a bit more explicit.
I don't know the overall landscape of your app, but you may want to do:
router.get('/user/:userName', userController.paramByUsername);
router.get('/id/:id', userController.paramByUserId);
Or, you could use the query string with URLs like this:
/search?user=John
/search?id=4889
And, then you'd just have one route:
router.get("/search", ....);
And you would examine which properties are present in req.query to decide which item you were looking for.

Best way to retrieve and filter a directus collection inside a custom endpoint?

I would need to search an item inside a collection and then work on that item.
What is the correct way to query a collection inside a custom endpoint?
Should i use the API or do you provide any classes?
I tried to follow the current guide https://github.com/directus/docs/blob/master/api/data.md
but i get a 403 (Forbidden) error.
I came around the same problem and now working with directus for some time. I asked the same question at the discussion section but the example in the guidebook should help:
export default (router, { services, exceptions }) => {
const { ItemsService } = services;
const { ServiceUnavailableException } = exceptions;
router.get('/', (req, res, next) => {
const recipeService = new ItemsService('recipes', { schema: req.schema, accountability: req.accountability });
recipeService
.readByQuery({ sort: ['name'], fields: ['*'] })
.then((results) => res.json(results))
.catch((error) => {
return next(new ServiceUnavailableException(error.message));
});
});
};
Maybe it is a bit late but hopefully it inspires others. Directus is from my first experiences now really great and worth to try.

Loopback3 - Find current user by access token

I have read in Loopback3 docs that getCurrentContext() has been deprecated. What I'd like to do is grab the access token and use that to find the associated user in the db, so I can get a company_id that the user belongs to and alter the query to include that in the where clause. I am using MySQL and a custom UserAccount model which extends from User.
I am new to Loopback so struggling to figure this out especially as most of the online help seems to point to getCurrentContext();.
I've set up some middleware to run on the parse phase:
middleware.json
"parse": {
"./modifyrequest": {
"enabled": true
}
}
modifyrequest.js
var loopback = require('loopback');
module.exports = function(app) {
return function tracker(req, res, next) {
console.log('Middleware triggered on %s', req.url);
console.log('-------------------------------------------------------------------');
console.log(req.accessToken);
}
};
However req.accessToken is always undefined. I have added to server.js:
app.use(loopback.token());
Any ideas? Is this the wrong approach ?
SOLUTION
As per Kamal's comment below...
Try setting "loopback#token": {} in middleware.json under "initial:before"
This populates req.accessToken
First, try setting "loopback#token": {} in middleware.json under "initial:before".
Then, if you are accessing accessToken from request object, you can find the userId within that accessToken object. Try to log req.accessToken, you will find the userId therein.
You can use that user id to search for corresponding user in the database.
User.findById(req.accessToken.userId, function(err, user){
if(err) {
//handle error
}
else {
//access user object here
}
});