Nuxt.js: Middleware arguments

Created on 19 Sep 2017  路  39Comments  路  Source: nuxt/nuxt.js

SImple question: Is it possible to pass arguments to a middleware?

For ex:

middleware: [
    middlewareName({myProp: 'myValue'})
]

This feature request is available on Nuxt.js community (#c1511)
available soon enhancement

Most helpful comment

@mtnptrsn actually we have even a better solution :)

With vue-router, they recommend to use meta for handling this kind of strategy, I am currently implement this meta property directly into the pages components.

Example:

<template>
  <h1>Only an admin can see this page</h1>
</template>

<script>
export default {
  middleware: 'auth',
  meta: {
    auth: { authority: 2 }
  }
}
</script>

Then in your middleware/auth.js:

export default ({ store, route, redirect }) => {
  // Check if user is connected first
  if (!store.getters['user/user'].isAuthenticated) return redirect('/login')

  // Get authorizations for matched routes (with children routes too)
  const authorizationLevels = route.meta.map((meta) => {
    if (meta.auth && typeof meta.auth.authority !== 'undefined')
      return meta.auth.authority
    return 0
  })
  // Get highest authorization level
  const highestAuthority = Math.max.apply(null, authorizationLevels)

  if (store.getters['user/user'].details.general.authority < highestAuthority) {
    return error({
      statusCode: 401,
      message: 'Du m氓ste vara admin f枚r att bes枚ka denna sidan.'
    })
  }
}

All 39 comments

Maybe you can pass a value to the state and read it in the middleware. not sure.

@christophwolff Gotcha. This feature would be really good to have, though!

since the middleware receives the context you can use everything that is in it. So for example context.env variables or the context.store. So if you want to set something globally put the value in the env varables in your nuxt.config.js and check them in the middleware. If you need to modify the value at runtime you should use the store since you can use nuxtServerInit to put data before rendering inside it.

@vuchl Not really what I want tho. Different pages need different arguments. My example:

export default ({ req, error, isServer, isClient, redirect, store }) => {
    const serverAuthed = (
        isServer &&
        req.session &&
        req.session.userIsAuthenticated &&
        req.session.user.general.authority > 1
    );

    const clientAuthed = (
        isClient &&
        store.getters['user/user'] &&
        store.getters['user/user'].isAuthenticated &&
        store.getters['user/user'].details.general.authority > 1
    );

    if (!serverAuthed && !clientAuthed) {
        return error({
            statusCode: 401,
            message: 'Du m氓ste vara admin f枚r att bes枚ka denna sidan.'
        });
    }
}

(ignore the error message, it's in swedish)

I have different authority roles, and different pages needs a different 'authority' levels. Currently I have 3 files which looks exactly the same but with different authority requirment. That's why I want to pass an argument instead of having 3 files.

Ah so you look for authorization via middleware. I think you therefore need the roles of the logged in user set upon authentication and then read upon page visits, am I getting this right?

Also when the pages loads the first time it will throw an error since the isclient is false.

@vuchl The user is set upon authentication, the problem is that I can't pass arguments to the middleware. Some pages needs the user to be authority 2, some pages needs the user to have authority 1.

Id like to do this:

middleware: auth_middleware({ authority: 0})

```javascript
middleware: auth_middleware({ authority: 1})

```javascript
middleware: auth_middleware({ authority: 2})

Instead of having different files for every authority level, doing like this:

middleware: 'auth_verified'

```javascript
middleware: 'auth_admin'

```javascript
middleware: 'auth_guest'

Hope this makes it more clear.

Hmm I guess you then can unly use the store for that. But that couples it pretty tightly. So you save the user to the store upon authentication. Also save the authority level. then then in the middleware check the store.

Yeah but the pages requires different authority levels. I cant check the store for that.

So you need to set a property on the page then then and check that against the user in the middleware.

Yes. That would solve it.

the thing is, the middleware is called before the page, right? so you have no knowledge of the properties of the page when the middleware is ran 馃檲

Yup. Quite a tough one!

maybe register a route.afterEach?

As another workaround you could go with the validate() method

@vuchl True. I'll try that.

@vuchl The problem with validate is that I can only show a 404 error page. I'd like to show a custo error page with error code 401. Good solution though!

Oh boy. This is not a "simple question" anymore 馃槃

Maybe you can get the context in the validate funtion somehow and from there the redirect funtion to redirect to your custom error page.

@vuchl Haha, still a simple question, just a complicated answer ;) Hmm, yeah then I'd just rather have multiple files I think. I guess I'll have to live with that. But I'd love Nuxt to have arguments for middlewares.

Yes for now that seems to be the only valuable solution. I thought of extending the validate method to receive also the redirect method but that seems to be a bit out of the scope of validate(). I think we should introduce something like an authorize() method on a page. But this should not be in v1 since it would change the API.

what are your thoughts here @Atinux and @alexchopin?

@vuchl That's actually not a bad idea!

Hi,
We have thought about middleware arguments once we have created this module.
As parameters are static, the first idea was to use it like that:

middleware: 'role:editor'

However, we thought that it's maybe more readable to do this:

middleware: ['isEditor', 'isAdmin']

instead of this:

middleware: 'role:editor,admin'

@alexchopin Do you mean it's more legible when it's multiple files vs being able to send arguments?

@mtnptrsn actually we have even a better solution :)

With vue-router, they recommend to use meta for handling this kind of strategy, I am currently implement this meta property directly into the pages components.

Example:

<template>
  <h1>Only an admin can see this page</h1>
</template>

<script>
export default {
  middleware: 'auth',
  meta: {
    auth: { authority: 2 }
  }
}
</script>

Then in your middleware/auth.js:

export default ({ store, route, redirect }) => {
  // Check if user is connected first
  if (!store.getters['user/user'].isAuthenticated) return redirect('/login')

  // Get authorizations for matched routes (with children routes too)
  const authorizationLevels = route.meta.map((meta) => {
    if (meta.auth && typeof meta.auth.authority !== 'undefined')
      return meta.auth.authority
    return 0
  })
  // Get highest authorization level
  const highestAuthority = Math.max.apply(null, authorizationLevels)

  if (store.getters['user/user'].details.general.authority < highestAuthority) {
    return error({
      statusCode: 401,
      message: 'Du m氓ste vara admin f枚r att bes枚ka denna sidan.'
    })
  }
}

@Atinux Wow, that's awesome! Thank you! This should def be included in the documentation.

Thank you so much!

Yes, but right now it's not implemented @mtnptrsn

You have to be a bit patient!

@Atinux Oh, right. Thought you said that was already implemented, soz. That's great tho, great work!

@Atinux looks nice! So we need to wait for you guys to implement the merging of meta: {auth: ''} into route.meta? Sounds fair!

Yes :)

This will be released with 1.0?

@Atinux I hope that feature will release soon.

Same here. I think route meta is very useful for conditional rendering in parent routes or root. Can't wait..

What about if any logged user goes to chrome developer pannel and use $nuxt.$store.commit(...) to change it's authority level?? How to avoid it?

@Atinux there is no way to use metas introduced into head () function to handle auth using your example ? Tenants of my SaaS application are able to create custom pages and fill meta tags for each one. It would be awesome if they could add auth meta to give access to page for their users.
PS: I know middleware is executed before fetching data. I'm open to any advices. In store I set every role of each user and tenant admin can create new roles for their users

@hAppywAy I am not sure to understand fully what you want to achieve. You can use the store to know the rights of your users and then use head() to add more meta tags depending of the user.

@hAppywAy I am not sure to understand fully what you want to achieve. You can use the store to know the rights of your users and then use head() to add more meta tags depending of the user.

Are there still plans to merge meta: {} into route.meta? I'd like to be able to use meta properties to define page specific features outside of the main component. For example, using a meta property to define a header theme, or to disable certain features in my footer.

Thanks.

Hi @SteveEdson

Could you please create a pull request on http://cmty.app/nuxt so we can keep track of it please?

@Atinux done at #3751. Thanks

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shyamchandranmec picture shyamchandranmec  路  3Comments

jaredreich picture jaredreich  路  3Comments

mikekidder picture mikekidder  路  3Comments

maicong picture maicong  路  3Comments

danieloprado picture danieloprado  路  3Comments