【发布时间】:2020-06-26 03:15:48
【问题描述】:
现状
我正在开发 nodejs 后端服务器和 vue 前端应用程序,它们在不同的端口(localhost:3000 和 localhost:8080)下运行。为了启用 CORS 连接,我从 vue.config.js 文件中配置了 devServer 代理。
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 响应状态。
研究和试验至今
在我继续尝试之前,我应该首先介绍要操作的强制代码。不知何故,这至少解释了其中 vuex 操作使用 axios,axios 最终使用后端路由器。
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>
Tasks.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()
}
}
现在我需要介绍一下我尝试解决的问题
-
配置CORS 选项
由于这个错误页面没有显示任何应该在请求头中设置的授权头,我想出了我启用 cors 连接的方式,我相信这会启用预检请求。这是我从后端代码配置的中间件行为。 task.js(快速路由文件)
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
auth.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
- 登录后设置Authorization header为axios默认header
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)
}
}
- 快速路由上的中间件链接(cors, auth)
我在同一个后端代码(task.js)上尝试了两个不同的中间件
router.get('/tasks', [cors(corsOptions), auth], async (req, res) => {
// same as previously attached code
}
现在我相信引用 another post with similar issue 会帮助我,但它是关于启用 CORS,而不是标题不是通过预检请求或其他类型的请求发送的问题。
【问题讨论】:
标签: node.js express authentication cors vuex