Laravel 4 Auth Filter: Unable to generate a URL for the named route as such route does not exist - authentication

I am trying to restrict a resource that I have named Artists (run by an ArtistsController). I tried doing this directly with the constructor in the controller:
public function __construct()
{
$this->beforeFilter('auth', array('except' => array()));
}
And in my filters, I have:
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::route('fans/landing');
});
In my routes, I have:
Route::get('fans/landing', array('uses' => 'FansController#getIndex'))->before('guest');
However, when I run this (trying to go to one of the resource pages), I get the following error:
Unable to generate a URL for the named route "fans/landing" as such route does not exist.
This is strange, because when I remove the construct function, the fans/landing page loads fine. Also, it redirects another page (not part of the resource), fine to fans/landing, when I have:
Route::get('/fans/home', array('uses' => 'FansController#getHome'))->before('auth');

change
Route::get('fans/landing', array('uses' => 'FansController#getIndex'))->before('guest');
to
Route::get('fans/landing', array('as' => 'fans.landing', 'uses' => 'FansController#getIndex'))->before('guest');
and change
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::route('fans/landing');
});
to
Route::filter('auth', function()
{
if (Auth::guest()) return Redirect::route('fans.landing');
});

Related

Dynamically add a route in a Nuxt3 middleware

I have a Nuxt3 project where I'd like to add new routes based on an API call to a database. For example, let's say a user navigates to /my-product-1. A route middleware will look into the database and if it finds an entry, it will return that a product page should be rendered (instead of a category page, for example).
This is what I came up with:
export default defineNuxtPlugin(() => {
const router = useRouter()
addRouteMiddleware('routing', async (to) => {
if (to.path == '/my-awesome-product') {
router.addRoute({
component: () => import('/pages/product.vue'),
name: to.path,
path: to.path
})
console.log(router.hasRoute(to.path)) // returns TRUE
}
}, { global: true })
})
To keep it simple, I excluded the API call from this example. The solution above works, but not on initial load of the route. The route is indeed added to the Vue Router (even on the first visit), however, when I go directly to that route, it shows a 404 and only if I don't reload the page on the client does it show the correct page when navigated to it for the second time.
I guess it has something to do with the router not being updated... I found the following example in a GitHub issue, however, I can't get it to work in Nuxt3 as (as far as I'm aware) it doesn't provide the next() method.
When I tried adding router.replace(to.path) below the router.addRoute line, I ended up in an infinite redirect loop.
// from https://github.com/vuejs/vue-router/issues/3660
// You need to trigger a redirect to resolve again so it includes the newly added
route:
let hasAdded = false;
router.beforeEach((to, from, next) => {
if (!hasAdded && to.path === "/route3") {
router.addRoute(
{
path: "/route3",
name: "route3",
component: () => import("#/views/Route3.vue")
}
);
hasAdded = true;
next('/route3');
return;
}
next();
});
How could I fix this issue, please?
Edit:
Based on a suggestion, I tried using navigateTo() as a replacement for the next() method from Vue Router. This, however, also doesn't work on the first navigation to the route.
let dynamicPages: { path: string, type: string }[] = []
export default defineNuxtRouteMiddleware((to, _from) => {
const router = useRouter()
router.addRoute({
path: to.path,
name: to.path,
component: () => import ('/pages/[[dynamic]]/product.vue')
})
if (!dynamicPages.some(route => route.path === to.path)) {
dynamicPages.push({
path: to.path,
type: 'product'
})
return navigateTo(to.fullPath)
}
})
I also came up with this code (which works like I wanted), however, I don't know whether it is the best solution.
export default defineNuxtPlugin(() => {
const router = useRouter()
let routes = []
router.beforeEach(async (to, _from, next) => {
const pageType = await getPageType(to.path) // api call
if (isDynamicPage(pageType)) {
router.addRoute({
path: to.path,
name: to.path,
component: () => import(`/pages/[[dynamic]]/product.vue`),
})
if (!routes.some(route => route.path === to.path)) {
routes.push({
path: to.path,
type: pageType,
})
next(to.fullPath)
return
}
}
next()
})
})
I suggest you use dynamic routing within /page directory structure - https://nuxt.com/docs/guide/directory-structure/pages#dynamic-routes
The [slug] concept is designed exactly for your usecase. You don't need to know all possible routes in advance. You just provide a placeholder and Nuxt will take care of resolving during runtime.
If you insist on resolving method called before each route change, the Nuxt's replacement for next() method you're looking for is navigateTo
https://nuxt.com/docs/api/utils/navigate-to
And I advise you to use route middleware and put your logic into /middleware/routeGuard.global.ts. It will be auto-executed upon every route resolving event. The file will contain:
export default defineNuxtRouteMiddleware((to, from) => {
// your route-resolving logic you wanna perform
if ( /* navigation should happen */ {
return navigateTo( /* your dynamic route */ )
}
// otherwise do nothing - code will flow and given to.path route will be resolved
})
EDIT: However, this would still need content inside /pages directory or some routes created via Vue Router. Because otherwise navigateTo will fail, as there would be no route to go.
Here is an example of one possible approach:
https://stackblitz.com/edit/github-8wz4sj
Based on pageType returned from API Nuxt route guard can dynamically re-route the original URL to a specific slug page.

Select a layout for dynamically generated nuxt page

I'm building a project where all my data - including page routes - comes from a GraphQL endpoint but needs to be hosted via a static site (I know, I know. Don't get me started).
I've managed to generate routes statically from the data using the following code in nuxt.config.js:
generate: {
routes: () => {
const uri = 'http://localhost:4000/graphql'
const apolloFetch = createApolloFetch({ uri })
const query = `
query Pages {
pages {
slug
template
pageContent {
replaced
components {
componentName
classes
body
}
}
}
}
`
return apolloFetch({ query }) // all apolloFetch arguments are optional
.then(result => {
const { data } = result
return data.pages.map(page => page.slug)
})
.catch(error => {
console.log('got error')
console.log(error)
})
}
}
The problem I am trying to solve is that some pages need to use a different layout from the default, the correct layout to use is specified in the GraphQL data as page.template but I don't see any way to pass that information to the router.
I've tried changing return data.pages.map(page => page.slug) to:
return data.pages.map(page => {
route: page.slug,
layout: page.template
})
but that seems to be a non-starter. Does anyone know how to pass a layout preference to the vue router?
One way would be to inject the data into a payload
https://nuxtjs.org/api/configuration-generate#speeding-up-dynamic-route-generation-with-code-payload-code-
This will allow you to pass generate information into the route itself.

How to redirect to another router from an AuthorizedStep

I have two routes — one is a public router and the other is the authorized router.
In my authorized router I have an authorizeStep.
The authorizedStep checks if there is a token in localStorage and if it is returns a next().
However if it fails to find a token its supposed to stop and jump out returning to the public router.
I am having trouble stopping the authorized step and instead going to the public router.
I have:
run(navigationInstruction: NavigationInstruction, next: Next): Promise<any> {
return Promise.resolve()
.then(() => this.checkSessionExists(navigationInstruction, next)
.then(result => result || next())
);
}
checkSessionExists(navigationInstruction: NavigationInstruction, next: Next) {
const session = this.authService.getIdentity();
if (!session) {
// HOW DO I CANCEL THE NEXT HERE AND GO TO THE PUBLIC ROUTER?
return next.cancel(new Redirect('login'))
}
return next()
}
forceReturnToPublic() {
this.authService.clearIdentity();
this.router.navigate("/", { replace: true, trigger: false });
this.router.reset();
this.aurelia.setRoot("public/public/public");
}
I have the function forceReturnToPublic() however I want to go and cancel the next() then go directly to the other router... I dont want to redirect..
How do I cancel the next in the promise and reset the router?
Here is my boot.ts which should kick it back to public but I dont know how to jump out of the promise cleanly...
// After starting the aurelia, we can request the AuthService directly
// from the DI container on the aurelia object. We can then set the
// correct root by querying the AuthService's checkJWTStatus() method
// to determine if the JWT exists and is valid.
aurelia.start().then(() => {
var auth = aurelia.container.get(AuthService);
let root: string = auth.checkJWTStatus() ? PLATFORM.moduleName('app/app/app') : PLATFORM.moduleName('public/public/public');
aurelia.setRoot(root, document.body)
});
If I place the forceReturnToPublic() in place of the return next.cancel(new Redirect('login') it goes into and endless loop with errors.
EDIT
I found THIS question which indicates I should add "this.pipeLineProvider.reset()" so I did - like this...
forceReturnToPublic() {
this.pipelineProvider.reset();
this.authService.clearIdentity();
this.router.navigate("/", { replace: true, trigger: false });
this.router.reset();
this.aurelia.setRoot("public/public/public");
}
Whilst it goes straight back to the public route I get an error in the console.
aurelia-logging-console.js:47 ERROR [app-router] Error: There was no router-view found in the view for ../components/clients/clientList/clientList.
at _loop (aurelia-router.js:281)
at NavigationInstruction._commitChanges (aurelia-router.js:307)
at CommitChangesStep.run (aurelia-router.js:143)
at next (aurelia-router.js:112)
at iterate (aurelia-router.js:1272)
at processActivatable (aurelia-router.js:1275)
at ActivateNextStep.run (aurelia-router.js:1161)
at next (aurelia-router.js:112)
at iterate (aurelia-router.js:1191)
at processDeactivatable (aurelia-router.js:1194)
I was clicking on the clientList nav link which does have a router-view..
How/where do I place the pipelineProvider.reset()? (if this is the problem)
But what I really want is...
How do I stop this router and cleanly move to the other router?
As you do I keep trying things.. This worked for me as I believe the pipelineProvider needed to finish before moving to the next step.. So I used a promise like so:
forceReturnToPublic(): Promise<any> {
return Promise.resolve()
.then(() => this.pipelineProvider.reset())
.then(() => this.authService.clearIdentity())
.then(() => this.router.navigate("/", { replace: true, trigger: false }))
.then(() => this.router.reset())
.then(() => this.aurelia.setRoot(PLATFORM.moduleName('public/public/public')));
}
...and no errors.

CakePHP3 Auth redirectURL route broken

I have a controller with a particular method to login:
public function login() {
if ($this->request->is('post')){
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
// not logged
$this->Flash->error('Your username or password is incorrect');
}
}
and default route looks like
Router::scope('/', function (RouteBuilder $routes) {
$routes->fallbacks(DashedRoute::class);
});
after user is logged in CakePHP throws an error
Error: A route matching "/" could not be found.
None of the currently connected routes match the provided parameters.
Add a matching route to config/routes.php
when IMO it should to redirect to the page (based on a related controller) from where login method was executed.
Login code is based on that tutorial.
Any thoughts?
To solve this issue:
Please update the below lines in routes.php file
Router::defaultRouteClass('DashedRoute');
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect('/', ['controller' => 'users', 'action' => 'index']);
$routes->fallbacks('DashedRoute');
});
Plugin::routes();
Please do create index() in users controller.
Let me know if any issue.

Auth Filter Not Working

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);
}
});