最近一直在使用 jwt,前端通过用户名、密码登陆成功后,接口返回一个 jwt
// login
exports.user_login = async function (req, res, next) {
const { username, password } = req.body
let ret = await userModel.userLogin(username, password)
if (!ret) return next(createError(500)) // sql 执行失败,直接给 500
if (ret.length !== 1) { // 用户名或密码错误
res.json({
code: 100,
message: '用户名或密码错误',
data: null
})
} else {
const user = ret[0]
const token = generateJWT(user)
res.json({
code: 100,
message: '返回成功',
data: {
token
}
})
}
}
// 生成 jwt
function generateJWT(user) {
let now = new Date()
let expire = new Date(now).getTime() + 30 * 60 * 1000 // 30 min 后过期
return jwt.sign({
id: user.id,
username: user.username,
password: user.password,
role: user.role,
exp: expire / 1000
}, SECRET)
}
前端请求成功后,收到 token,存储在本地
// vuex store 中
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({ username: username.trim(), password }).then(res => {
if (res) {
commit('SET_TOKEN', res.token)
setSessionItem('token', res.token) // 存到 sessionStorage 中
resolve(true)
} else {
resolve(false)
}
}).catch(error => {
console.log('error: ', error) // for debug
reject(error)
})
})
}
然后以后每次请求接口都带上这个 jwt
// 请求拦截器
axios.interceptors.request.use(
config => {
const token = getSessionItem('token') || ''
if (token) config.headers['token'] = token
return config
},
error => {
// 对请求错误做些什么
console.log(error) // for debug
return Promise.reject(error)
}
)
之前做移动端是这么搞的,但今天在做 PC 端一个管理后台时,发现 jwt 存到 sessionStorage 中有个问题,同源下,不同的窗口 sessionStorage 中的数据不能共享,就是说打开一个窗口已经登录了,在浏览器中在开一个窗口还得重新登录,这就不能忍了
于是,就想成功后,将 jwt 存到 cookie 中,这样不同的窗口就可以共享了,这个存储后端和前端都可以做,后端存储:
// login
exports.user_login = async function (req, res, next) {
...
const user = ret[0]
const token = generateJWT(user)
// express 要引入 cookie-parse
res.cookie("token", token, { maxAge: 30 * 60 * 1000, httpOnly: true }) // httpOnly 为 true,js 脚本就不能访问了
res.json({
code: 100,
message: '登录成功'
})
}
返回头就会有 set-cookie 这个字段了
以后每个请求头里面都会自带 cookie 了
express 接收:req.cookies.token
本着前后端完全分离的原则,我采用前端来存 cookie,后端将生成的 token 还是给到前端,前端引 js-cookie 这个库来操作
// vuex store 中
login({ commit }, userInfo) {
...
if (res) {
commit('SET_TOKEN', res.token)
setToken(res.token)
resolve(true)
} else {
resolve(false)
}
...
}
用 js-cookie 这个库设置 cookie,没有找到怎么设置 HttpOnly。