如何在 Vuejs 和 Node 中设置授权标头并保护路由

Posted

技术标签:

【中文标题】如何在 Vuejs 和 Node 中设置授权标头并保护路由【英文标题】:How to set authorization header and protect routes in Vuejs and Node 【发布时间】:2020-02-14 01:35:12 【问题描述】:

我正在使用 passport-jwt 策略来保护我的应用程序中的 auth 用户,一旦我登录,我就会生成一个 jwt-token 现在我想保护我的欢迎页面溃败,以便用户在没有登录的情况下无法打开它

所以当我登录时,我会像这样用payload 创建jwt-token

我的 user.js 文件

const payload =  email: rows[0].email  // jwy payload
            console.log('PAYLOAD')
            console.log(payload)
            jwt.sign(
                payload,
                key.secretOrKey,  expiresIn: 3600 ,
                (err, token) => 
                    res.json(
                        success: true,
                        token: 'Bearer ' + token,
                        email
                    )

                )

现在在我的 passport.js 中,我正在这样做

   const opts = ;

opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;

passport.use(new JwtStrategy(opts, (jwt_payload, done) => 

    let payLoadEmail = jwt_payload.email //payload data what I have passed in creating jwt 
    console.log("payload email :" + payLoadEmail)
    User.fetchLogedInUser(payLoadEmail)
        .then(([rows]) => 
            if (rows.length > 0) 
                return done(null, rows[0].email) // returning data what I need
            
            return done(null, false)
        )
        .catch(err => console.log(err))

));

两者都工作正常。

现在我想在我的 router.js 文件中保护我的欢迎路由

    const express = require('express');
const router = express.Router();
const passport = require('passport')


const UsersCtrl = require('../controllers/users');

router.use('/login', UsersCtrl.login)
router.use('/welcome',passport.authenticate('jwt',session:false))
router.use('/logout', UsersCtrl.logout)


module.exports = router;

假设用户在没有登录的情况下输入localhost:8080/welcome,那么我想保护它

所以在我的 store.js 文件中,当用户登录时,我在登录点击时执行此操作,并且我创建了一个方法 getAuthUser。我不知道如何通过此配置来保护我的欢迎文件

这是我完整的 store.js 代码

    import axios from 'axios'
import jwt from 'jsonwebtoken'

function checkTokenValidity(token)   // token validity
    if (token) 
        const decodedToken = jwt.decode(token)
        return decodedToken && (decodedToken.exp * 1000) > new Date().getTime()

    
    return false

export default 
    namespaced: true,
    state: 
        user: null,
        isAuthResolved: false   // this I am calling on my login page i am confused where should I call this or not to call this
    ,
    getters: 
        authUser(state) 
            return state.user
        ,
        isAuthenticated(state) 
            return !!state.user
        
    ,
    actions: 
        loginWithCredentials( commit , userDate) 
            return axios.post('/api/v1/users/login', userDate)
                .then(res => 
                    const user = res.data
                    console.log(user.email)
                    localStorage.setItem('jwt-token', user.token)
                    commit('setAuthUser', user)
                )
        ,

        logout( commit ) 
            return new Promise((resolve, reject) => 
                localStorage.removeItem('jwt-token')
                commit('setAuthUser', null)
                resolve(true)
            )

        ,

        getAuthUser( commit, getters ) 
            const authUser = getters['authUser']
            const token = localStorage.getItem('jwt-token')
            const isTokenValid = checkTokenValidity(token)
            if (authUser && isTokenValid) 
                return Promise.resolve(authUser)
            

            const config =   // here what to do with this how can I pass this to protect my route
                headers: 
                    'cache-control': 'no-cache',
                    'Authorization': token
                
            

        

    ,
    mutations: 
        setAuthUser(state, user) 
            return state.user = user
        ,
        setAuthState(state, authState) 
            return state.isAuthResolved = authState
        
    

在我的 route.js vue 文件中

    import Vue from 'vue'
import Router from 'vue-router'
import store from './store'

Vue.use(Router)

const router = new Router(
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        path: '/welcome',
        name: 'welcome',
        meta:  onlyAuthUser: true ,
        component: () =>
            import ('./views/Welcome.vue'),


    , ]
)
router.beforeEach((to, from, next) => 
    store.dispatch('auth/getAuthUser')
        .then((authUser) => 
            const isAuthenticated = store.getters['auth/isAuthenticated']

            if (to.meta.onlyAuthUser) 
                if (isAuthenticated) 
                    next()
                 else 
                    next( name: 'PageNotAuthenticated' )
                
             else if (to.meta.onlyGuestUser) 
                if (isAuthenticated) 
                    next( name: 'welcome' )
                 else 
                    next()
                
             else 
                next()
            
        )
)

export default router

我的主要问题是我想保护路由并让用户使用 jwt 和护照进行身份验证我在登录后得到 jwt 并且想要检查我的受保护路由是否可以访问而无需登录后端。

在前端 (vue.js) 我的存储文件在运行> getAuthUsers 我不知道如何将配置传递给其他路由,比如我的欢迎。

【问题讨论】:

【参考方案1】:

不确定我是否完全理解您的问题,因为您似乎正确地实现了路由访问。您只需将路由添加为数组,而其余代码保持不变。

const router = new Router(
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        path: '/welcome',
        name: 'welcome',
        meta:  onlyAuthUser: true ,
        component: () =>
            import ('./views/Welcome.vue'),


    ,
    
        path: '/login',
        name: 'Login',
        meta:  onlyGuesUser: true ,
        component: () =>
            import ('./views/Login.vue'),


    ]
)

对于使用Authentication: Bearer xxxxxxxx,您可以修改axios 代码以直接使用所需的标头,而不是每次都通过路由传递它。创建一个名为services 的新文件夹和一个名为base-api 的文件。显然,您可以随意命名,但这是我的设置。

import axios from 'axios';

export default () => 
  let headers = 
    'cache-control': 'no-cache'
  ;
  let accessToken = localStorage.getItem('jwt-token');
  if (accessToken && accessToken !== '') 
     headers.Authorization = accessToken;

  ;
  return axios.create(
    baseURL: 'SECRET_URL_',
    headers: headers
  );

将此文件导入您的store.js。将import axios from 'axios' 替换为import axios from '@src/services/base-api.js。当文件返回一个 axios 实例时,您需要以axios() 访问它。这意味着你的功能将是

return axios().post('/api/v1/users/login', userDate)
                .then(res => 
                    // do whatever
                )

【讨论】:

嘿,base-api.js headers.Authorization = Bearer $jwt-token; 代替 Bearer$jwt-token 我可以像这样简单地通过 headers.Authorization = accessToken `因为我已经在 Bearer 前缀中获得了令牌? 是的,这完全取决于你,我添加了一个单词用于演示如何进一步编辑标题。 嘿,我应该在 base-api.js baseURL: 'SECRET_URL_',987654335@ 中传递什么网址 嗯,你正在做axios.post('/api/v1/users/login', userDate),所以假设实际的网址是http://localhost:8000/api/v1/users/login,那么你将通过http://localhost:8000/作为基本网址。

以上是关于如何在 Vuejs 和 Node 中设置授权标头并保护路由的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ng2-signalr 中设置授权标头?

如何使用 nodejs 设置授权标头并表达

express-jwt 和带有 cookie 的 Angular 9:未在“授权”标头中设置令牌

在Node.js SOAP客户端中设置授权

在 URL 中设置请求标头?

如何在 laravel、vuejs 应用程序中设置 Paystack