Nuxtjs Auth模块在中间件中不起作用

时间:2020-10-20 12:06:36

标签: nuxt.js nuxtjs

嗨,我发现了一个类似于我的老问题,在StackOverFlow上没有答案:nuxtjs/auth axios not sending cookie

也在GitHub上,没有有效的解决方案:https://github.com/nuxt-community/auth-module/issues/478

所以问题是,如果我在任何页面中调用$auth.loggedIn,它就像一个超级按钮,但是如果我在自定义身份验证中间件中进行调用(或者如果我使用默认的auth中间件),它总是返回false

我在nuxt.config.js中的身份验证配置

auth: {
    strategies: {
      local: {
        endpoints: {
          login: {
            url: '/rest-auth/login/',
            method: 'post',
            propertyName: 'key',
          },
          logout: { url: '/rest-auth/logout/', method: 'post' },
          user: {
            url: '/rest-auth/user/',
            method: 'get',
            propertyName: false,
          },
        },
        tokenType: 'Token',
        tokenName: 'Authorization',
      },
      redirect: {
        login: '/user_dashboard',
        home: '/',
      },
    },
  },

我的自定义身份验证中间件

export default async function ({ $auth, redirect }) {
  const user = await $auth.loggedIn
  console.log(user) // <-- this always return false for some reason :(
  if (user) {
    // let the user see the page
  } else {
    // redirect to homepage
    redirect('/')
  }
}

编辑:

根据要求,这是我的package.json:

{
  "name": "<MY_APP_NAME>",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "lint:style": "stylelint **/*.{vue,css} --ignore-path .gitignore",
    "lint": "npm run lint:js && npm run lint:style",
    "test": "jest"
  },
  "lint-staged": {
    "*.{js,vue}": "eslint",
    "*.{css,vue}": "stylelint"
  },
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
      "pre-commit": "lint-staged"
    }
  },
  "dependencies": {
    "@nuxt/content": "^1.9.0",
    "@nuxtjs/auth": "^4.9.1",
    "@nuxtjs/axios": "^5.12.2",
    "@nuxtjs/pwa": "^3.0.2",
    "cookie-universal-nuxt": "^2.1.4",
    "core-js": "^3.6.5",
    "nuxt": "^2.14.7",
    "nuxt-buefy": "^0.4.3"
  },
  "devDependencies": {
    "@commitlint/cli": "^11.0.0",
    "@commitlint/config-conventional": "^11.0.0",
    "@nuxtjs/eslint-config": "^3.1.0",
    "@nuxtjs/eslint-module": "^3.0.0",
    "@nuxtjs/style-resources": "^1.0.0",
    "@nuxtjs/stylelint-module": "^4.0.0",
    "@vue/test-utils": "^1.1.0",
    "babel-core": "7.0.0-bridge.0",
    "babel-eslint": "^10.1.0",
    "babel-jest": "^26.5.0",
    "eslint": "^7.10.0",
    "eslint-config-prettier": "^6.12.0",
    "eslint-plugin-nuxt": "^1.0.0",
    "eslint-plugin-prettier": "^3.1.4",
    "husky": "^4.3.0",
    "jest": "^26.5.0",
    "lint-staged": "^10.4.0",
    "node-sass": "^4.14.1",
    "prettier": "^2.1.2",
    "sass-loader": "^10.0.3",
    "stylelint": "^13.7.2",
    "stylelint-config-prettier": "^8.0.2",
    "stylelint-config-standard": "^20.0.0",
    "vue-jest": "^3.0.4"
  }
}

4 个答案:

答案 0 :(得分:1)

不幸的是,我无法使nuxtjs/auth在中间件中工作,但是我可以通过将cookie-universal-nuxtnuxtjs/auth结合使用来解决此问题:

您可以保持axios版本不变,无需为此解决方案降级

  1. npm install --save cookie-universal-nuxt
  2. 在您的cookie-universal-nuxt文件中添加nuxt.config.js
modules: [
    // other modules ...
    '@nuxtjs/auth',
    'cookie-universal-nuxt',
  ],
  1. 创建自定义auth中间件。我在中间件文件夹中叫我的auth-user
export default async function ({ app, redirect }) {
  // the following look directly for the cookie created by nuxtjs/auth
  // instead of using $auth.loggedIn
  const user = await app.$cookies.get('auth._token.local')
  if (user) {
    // let the user see the page
  } else {
    // redirect to homepage
    redirect('/')
  }
}
  1. 然后在您的应用程序的根页面中声明您的中间件,您只希望经过身份验证的用户才能访问它:
<script>
export default {
  middleware: ['auth-user'],
}
</script>

如果这不起作用,请通过在浏览器中打开开发人员工具/检查器来检查保存用户凭据的cookie名称。

答案 1 :(得分:1)

有同样的问题,我现在通过反复试验解决了这个问题。

服务器端不知道loginIn状态,因为他们没有实现它(?)。

所以我创建了自己的中间件,用于设置服务器端的状态。

创建: middleware / auth-ssr.ts

import { Context, Middleware } from '@nuxt/types';
import { parse as parseCookie } from 'cookie';
import jsonwebtoken from 'jsonwebtoken';
import { IJwtPayload } from '../../api/_types/types';

/**
 * This middleware is needed when running with SSR
 * it checks if the token in cookie is set and injects it into the nuxtjs/auth module
 * otherwise it will redirect to login
 * @param context
 */
const debugAuthMiddleware: Middleware = async (context: Context) => {
  if (process.server && context.req.headers.cookie != null) {
    try {
      const cookies = parseCookie(context.req.headers.cookie);
      const token = cookies['auth._token.local'] || '';
      const tokenWithoutBearer = token.replace('Bearer ', '');
      // console.log('headers.cookie token', token);
      // console.log('debugAuthMiddleware $auth 1', context.$auth.$state);
      if (!token || token.includes('false')) {
        // sometimes it stores 'Bearer false' when it unsets
        return;
      }
      const jwt: IJwtPayload = (jsonwebtoken.decode(tokenWithoutBearer) as unknown) as IJwtPayload;
      // console.log('jwt payload', jwt);
      if (!jwt) {
        return;
      }
      // console.log('set token ✅', jwt);
      await context.$auth.setToken('locale', tokenWithoutBearer);
      await context.$auth.setUser(jwt);
      context.$auth.$state.loggedIn = true;
    } catch (e) {
      console.error('debugAuthMiddleware', e);
    }
    // console.log('debugAuthMiddleware $auth 2', context.$auth.$state);
  }
};

export default debugAuthMiddleware;

然后在nuxt.config.ts中,我有这个中间件:

router: {
    middleware: ['user-agent', 'auth-ssr', 'auth'],
},

这是我的身份验证配置:

auth: {
    redirect: {
      logout: '/?signedOut=1',
      home: '/dashboard',
    },
    strategies: {
      local: {
        endpoints: {
          login: { url: '/api/v1/auth/login', method: 'post', propertyName: 'token' },
          logout: { url: '/api/v1/auth/logout', method: 'post' },
          user: { url: '/api/v1/user', method: 'get', propertyName: 'user' },
        },
        autoFetchUser: false, // do not fetch automatically! user object is coming from login api call
        rewriteRedirects: true, // If enabled, user will redirect back to the original guarded route instead of redirect.home.
        fullPathRedirect: true, // If true, use the full route path with query parameters for redirect
      },
    },
  },

然后服务器端nodejs / auth-middleware获取正确的登录状态+用户(我的JWT令牌包括userId,电子邮件,名称,范围:[])。

答案 2 :(得分:0)

它已经是“旧”帖子了,但我遇到了和你一样的问题。正如我所看到的,您正在使用 DRF。因此,我根据 Django-documentation-authentication 更改了 urls.py 并使用 obtain_auth_token 创建了 mylogin url,或者您可以创建自己的 LoginView。 另外,我用关键字 TokenAuthentication 创建了 Bearer 的子类,终于成功了! 例子: urls.py

from rest_framework.authtoken import views
path('api/login/',views.obtain_auth_token)

创建一个类似 authtoken.py

的文件
from rest_framework.authentication import TokenAuthentication
class TokenAuthentication(TokenAuthentication):
    keyword = 'Bearer'

Settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'myapp.authtoken.TokenAuthentication'
]

现在在nuxt.config.js

 auth: {
    strategies: {
      local: {
        user: {
          property: 'username',
        },
        endpoints: {
          login: { url: 'api/login/', method: 'post' },
          logout: { url: 'rest-auth/logout/', method: 'post' },
          user: { url: 'rest-auth/user/', method: 'get' }
        },
        tokenRequired:true,
        tokenType:'Bearer',
        autoFetchUser: false
      }
    }
  }

就这些,希望能帮到你!

更新

在我的 nuxt.config.js 上,我尝试了这个并且它在没有触及任何其他东西的情况下工作!

auth: {
    strategies: {
        local: {
          user: {
            property: 'username',
            autoFetch: true
          },

          endpoints: {

            login: { url: '/rest-auth/login/', method: 'post' },
            logout: { url: '/rest-auth/logout/', method: 'post' },
            user: { url: '/rest-auth/user/', method: 'get' },
          },
          token: {
            property: 'key',
            type: 'Token',
            name: 'Authorization',
          },
 
        }
      }
    }```

答案 3 :(得分:-1)

您是否尝试过使用不带 $ 符号的身份验证?那应该可以解决您的问题