Ошибка аутентификации после перезагрузки страницы (Vue, Expressjs с Nodejs) - PullRequest
0 голосов
/ 14 марта 2020

Текущая ситуация

Я занимаюсь разработкой nodejs внутреннего сервера и vue внешнего приложения, которое запускается на другом порту (localhost: 3000 и localhost: 8080). Чтобы включить соединение CORS, я настроил прокси-сервер devServer из файла vue .config. js.

vue .config. js

module.exports = {
    devServer: {
        proxy: {
            '/users': {
                target: 'http://127.0.0.1:3000/users',
                changeOrigin: true,
                pathRewrite: {
                    '^/users':''
                }
            },
            '/tasks': {
                target: 'http://127.0.0.1:3000/tasks',
                changeOrigin: true,
                pathRewrite: {
                    '^/tasks': ''
                }
            }
        }
    },
    outputDir: '../backend/public'
}

и использовал его технически cors. js для включения запроса к внутреннему серверу, который был реализован expressjs. Я отправляю запрос с компонентом vue для получения данных с внутреннего сервера. Он работает правильно, получая данные с сервера, и моя цель - сделать то же самое при перезагрузке страницы. Однако всякий раз, когда я перезагружаю ту же страницу, она постоянно отображает 401 http-статус ответа, установленный кодом бэкэнда, написанным мной.

введите описание изображения здесь

Исследование и Trial до

Прежде чем я go попыток, которые я попытался, я должен ввести обязательные коды, которые должны работать в первую очередь. Почему-то это, по крайней мере, объяснения, в которых действия vuex с использованием ax ios, ax ios с использованием внутренних маршрутизаторов в конечном итоге.

tasks.module. js

import axios from "axios"
import authHeader from '../../services/auth-header'

export const tasks = {
    state: {
        tasks: []
    },

    getters: {
        allTasks: (state) => state.tasks
    },

    actions: {
        async fetchTasks({ commit }) {
            const response = await axios.get('http://127.0.0.1:3000/tasks', {headers: authHeader()})

            commit('setTasks', response.data)

            axios.defaults.headers.common['Authorization'] = authHeader()
        },

        async addTask({ commit }, description) {
            const response = await axios.post('http://127.0.0.1:3000/tasks', { description, completed: false}, {headers: authHeader()})

            commit('newTask', response.data)
        },

        async updateTask({ commit }, updTask) {
            const response = await axios.patch('http://127.0.0.1:3000/tasks/'+updTask.id, updTask, {headers: authHeader()})

            commit('updateTask', response.data)
        }
    },

    mutations: {
        setTasks: (state, tasks) => (state.tasks = tasks),
        newTask: (state, task) => state.tasks.unshift(task),
        updateTask: (state, updTask) => {
            let updates = Object.keys(updTask)

            updates.forEach((update) => {
                state.task[update] = updTask[update]
            })
        }
    }
}

TaskManager. vue

<template>
  <div class="container">
    <div class="jumbotron">
      <h3>Task Manager</h3>
      <AddTask/>
      <Tasks/>
    </div>
  </div>
</template>

<script>
import Tasks from './components/Tasks'
import AddTask from './components/AddTask'

export default {
  name:'TaskManager',
  components: {
    Tasks,
    AddTask
  }
}
</script>

Задачи. vue

<template>
<div>
    <div>
        <div class="legend">
            <span>Double click to mark as complete</span>
            <span>
                <span class="incomplete-box"></span> = Incomplete
            </span>
            <span>
                <span class="complete-box"></span> = Complete
            </span>
        </div>
    </div>
    <div class="tasks">
        <div
            @dblclick="onDblClick(task)"
            v-for="task in allTasks"
            :key="task.id"
            class="task"
            v-bind:class="{'is-completed':task.completed}">
            {{task.description}}
        </div>
    </div>
</div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'
export default {
    name: "Tasks",
    methods:{
        ...mapActions(['fetchTasks', 'updateTask']),
        onDblClick(task) {
            const updTask = {
                id: task._id,
                description: task.description,
                completed: !task.completed
            }
            console.log(updTask)
            this.updateTask(updTask)
        }
    },
    computed: {
        ...mapGetters(['allTasks']),
    },
    created() {
        this.fetchTasks()
    }
}

Теперь мне нужно представить, что я пытался решить проблемы

  1. Настройка CORS options

    Так как на этой странице ошибки не отображался заголовок авторизации, который должен был быть установлен в заголовке запроса, я выяснил, как я включил соединение cors, и я полагаю, что это разрешает предварительный запрос. Вот то, что я настроил поведение промежуточного программного обеспечения из внутреннего кода. задача. js (express файл роутера)

const router = new express.Router()
const auth = require('../middleware/auth')
const cors = require('cors')
const corsOptions = {
    origin: 'http://127.0.0.1:3000',
    allowedHeaders: 'content-Type, Authorization',
    maxAge:3166950
}
router.options(cors(corsOptions))

router.get('/tasks', auth, async (req, res) => {
    const match = {}
    const sort = {}

    if(req.query.completed) {
        match.completed = req.query.completed === 'true'
    }

    if(req.query.sortBy) {
        const parts = req.query.sortBy.split('_')
        sort[parts[0]] = parts[1] === 'desc' ? -1:1             // bracket notation
    }

    try {
        await req.user.populate({
            path: 'tasks',
            match,
            options: {
                limit: parseInt(req.query.limit),
                skip: parseInt(req.query.skip),
                sort
            }
        }).execPopulate()
        console.log(req.user.tasks)
        res.status(200).send(req.user.tasks)
    } catch (e) {
        res.status(500).send(e)
    }
})
module.exports = router

аутентификация. js (промежуточное ПО)

const jwt = require('jsonwebtoken')
const User = require('../models/user')

const auth = async (req, res, next) => {
    try {
        const token = req.header('Authorization').replace('Bearer ','')
        const decoded = jwt.verify(token, 'thisisnewcourse')
        console.log('decoded token passed')
        const user = await User.findOne({ _id: decoded._id, 'tokens.token': token})
        console.log('user found')

        if(!user) {
            throw new Error()
        }
        req.token = token
        req.user = user
        next()

    } catch (error) {
        console.log('error caught')
        res.status(401).send({error: 'please authenticate'})
    }
}

module.exports = auth
Установить заголовок авторизации как ax ios заголовок по умолчанию после входа в систему

auth.module. js (так как вход в систему работает правильно, я копирую только часть действия входа в систему )

actions: {
        async login ({ commit }, user){
            try {
                const response = await axios.post('http://127.0.0.1:3000/users/login', user)

                if(response.data.token){
                    localStorage.setItem('user', JSON.stringify(response.data))

                    axios.defaults.headers.common['Authorization'] = `Bearer ${response.data.token}`
                }

                commit('loginSuccess', response.data)
            } catch (e) {
                console.log(e)
            }


        }
Связывание промежуточного ПО на маршруте express (cors, auth)

Я пробовал два разных промежуточных ПО на одном и том же бэкэнд-коде (задача. js)

router.get('/tasks', [cors(corsOptions), auth], async (req, res) => {
    // same as previously attached code
}

Теперь я считаю, что ссылка на еще один пост с похожей проблемой поможет мне, однако, это касается включения CORS, а не вопроса, что заголовок не отправляется ни с помощью предварительного запроса, ни с помощью других тип запросов.

1 Ответ

0 голосов
/ 14 марта 2020

Вы не включили код для authHeader, но я предполагаю, что он просто возвращает значение заголовка Authorization.

Этот бит мне кажется подозрительным:

async fetchTasks({ commit }) {
  const response = await axios.get('http://127.0.0.1:3000/tasks', {headers: authHeader()})

  commit('setTasks', response.data)

  axios.defaults.headers.common['Authorization'] = authHeader()
},

Последняя строка, похоже, пытается установить глобальный заголовок Authorization, чтобы он был включен во все последующие запросы ios. Это хорошо, но кажется странным не делать это раньше. У вас есть похожая строка внутри действия login, что имеет смысл, но я предполагаю, что она не вызывается при обновлении страницы.

Тогда есть этот бит:

{headers: authHeader()}

Если authHeader возвращает значение заголовка Authorization, это не будет работать. Вместо этого вам нужно:

{headers: { Authorization: authHeader() }}

В идеале вам не нужно устанавливать здесь какие-либо заголовки, а вместо этого вы просто устанавливаете глобальный заголовок, прежде чем пытаться выполнить этот запрос.

Хотя это не так прямая причина вашей проблемы, вы, кажется, перепутали провода о CORS. Вы настроили прокси, что означает, что вы не используете CORS. Ваш запрос относится к тому же источнику, поэтому CORS не применяется. Вам не нужно включать заголовки ответа CORS, если вы не делаете запрос кросс-источника. Если вы хотите сделать перекрестный запрос, не используйте прокси. Вы должны попытаться имитировать c вашу производственную среду во время разработки, поэтому, если вы собираетесь использовать CORS в рабочей среде, вы должны использовать ее во время разработки. В противном случае придерживайтесь прокси.

...