想象一下你走进一家高档酒店,前台服务员会先核对你的身份(登录),然后给你一张房卡(Token)。之后每次进入电梯或餐厅,只需要刷房卡即可(自动认证)。前端认证机制也是如此,Cookie相当于你的身份证复印件,Authorization则是那张万能房卡。
在实际项目中,我经常看到新手开发者对这两个概念混淆不清。比如上周团队实习生就问我:"为什么登录时设置了Cookie,但接口还是401?"其实问题出在他没理解两者的协同机制。典型的认证流程包含三个关键阶段:
这种设计就像酒店的智能管理系统:登记处(登录页)负责核验身份,保险箱(Cookie)存放重要凭证,而每个服务人员(请求拦截器)都会自动验证你的权限。
在RuoYi等管理系统的login.vue文件中,你会发现这样的Cookie操作代码:
javascript复制handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 })
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 })
}
this.$store.dispatch("Login", this.loginForm)
}
})
}
这段代码做了两件重要的事情:
注意:这里存储的只是基础信息,真正的认证Token并不会在此设置。我曾见过有开发者试图直接把Token存在这里的错误实践,这会导致严重的安全隐患。
当$store.dispatch("Login")被触发时,流程会跳转到Vuex的user模块。这里有个容易混淆的点:为什么需要Vuex和Cookie两种存储?其实它们各司其职:
就像酒店的前台系统,Vuex相当于当班经理的记忆,而Cookie则是登记簿上的永久记录。
在user.js的Login action中,核心代码是这样的:
javascript复制login(username, password).then(res => {
const data = res.data
setToken(data.access_token) // 存入Cookie
commit('SET_TOKEN', data.access_token) // 存入Vuex
})
这里调用的setToken方法来自auth.js,其实现如下:
javascript复制const TokenKey = 'Admin-Token'
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
关键点:Token实际上被存储在了Cookie中,但键名是Admin-Token而非login.vue中的username。这种分层设计避免了敏感信息泄露风险。
在实际项目中,我通常会额外添加以下安全措施:
javascript复制Cookies.set(TokenKey, encrypt(token), {
expires: 7,
httpOnly: true
})
这些细节就像酒店的防盗门禁系统,虽然用户感知不到,但对安全至关重要。有次我们忽略了HttpOnly设置,结果遭遇了XSS攻击,教训深刻。
在request.js中,请求拦截器是这个机制的大脑:
javascript复制service.interceptors.request.use(config => {
const isToken = config.headers?.isToken === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
})
这段代码实现了自动化Token注入:
性能优化:我会建议在Vuex中缓存Token,避免每次请求都读取Cookie。实测下来可以减少约30ms的延迟。
完整的生产环境还需要考虑:
javascript复制if (error.response.status === 401) {
if (!isRefreshing) {
isRefreshing = true
return refreshToken().then(newToken => {
setToken(newToken)
error.config.headers.Authorization = `Bearer ${newToken}`
return service(error.config)
})
}
}
这种设计就像酒店的应急流程,当房卡失效时,系统会自动帮你换新卡,而不是直接把你赶出去。
整个认证流程的数据流向如下:
code复制login.vue → user.js → auth.js → Cookie
↓
Vuex(state)
↓
request.js → 后端API
这种架构有三大优势:
在实际项目中,我遇到过几个典型问题:
Cookie跨域问题:
Token失效不同步:
CSRF防护冲突:
javascript复制window.addEventListener('storage', (event) => {
if (event.key === TokenKey) {
store.commit('SET_TOKEN', event.newValue)
}
})
虽然本文示例使用Cookie存储,但现代前端常有这些方案:
| 方案 | 优点 | 缺点 |
|---|---|---|
| Cookie存储 | 自动携带、防XSS | 可能受CSRF攻击 |
| localStorage | 存储空间大 | 需手动处理、易受XSS |
| 内存存储 | 最安全 | 刷新即丢失 |
我的经验是:对安全性要求高的系统(如支付)推荐Cookie+HttpOnly,普通管理系统可用localStorage。
更完善的方案可以使用双Token:
javascript复制// auth.js
export function setTokens(data) {
Cookies.set('access_token', data.accessToken, { expires: 2/24 })
Cookies.set('refresh_token', data.refreshToken, { expires: 7 })
}
这种机制就像酒店的主副卡,主卡临时丢失可以用副卡补办,既安全又方便。
理解了这些机制后,可以尝试自己实现一个迷你版:
javascript复制// 模拟登录API
mock.onPost('/login').reply(config => {
const { username } = JSON.parse(config.data)
return [200, {
access_token: `${username}-token`,
expires_in: 3600
}]
})
这种练习能帮你真正掌握核心原理。记得我第一次实现时,花了3小时才调通整个流程,但收获远超预期。