退出登录处理方案
# 执行步骤
- 清理掉当前用户缓存数据
- 清理掉权限相关配置
- 返回到登录页
# 主动退出
# 场景
退出登录触发时机一般有两种:
- 用户主动退出:用户点击登录按钮之后退出
- 用户被动退出:
token
过期或被其他人”顶下来“ 时退出
# 代码实现:
在 store/modules/user.js
中,添加对应 action
import router from '@/router'
logout() {
this.commit('user/setToken', '')
this.commit('user/setUserInfo', {})
removeAllItem()
router.push('/login')
}
2
3
4
5
6
7
8
为退出登录按钮添加点击事件,触发 logout
的 action
在 Navbar
中,添加对应 action
import { useStore } from 'vuex'
const store = useStore()
const logout = () => {
// 通过store.dispatch去触发user模块下的action
store.dispatch('user/logout')
}
2
3
4
5
6
7
# 被动退出
# 场景:
token
失效单用户登录:其他人登录该账号被 “顶下来”
# 处理方案:
- 主动处理:主要应对
token
失效 - 被动处理:同时应对
token
失效 与 单用户登录
# 被动退出解决方案之主动解决
背景:
我们知道
token
表示了一个用户的身份令牌,对 服务端 而言,它是只认令牌不认人的。所以说一旦其他人获取到了你的token
,那么就可以伪装成你,来获取对应的敏感数据。所以为了保证用户的信息安全,那么对于
token
而言就被制定了很多的安全策略,比如:
- 动态
token
(可变token
)- 刷新
token
- 时效
token
- ...
这些方案各有利弊,没有绝对的完美的策略。
而我们此时所选择的方案就是 时效 token
对于 token
本身是拥有时效的。通常情况下,这个时效都是在服务端进行处理。而此时我们要在 服务端处理 token
时效的同时,在前端主动介入 token
时效的处理中。 从而保证用户信息的更加安全性。
# 实现步骤:
- 在用户登录时,记录当前 登录时间
- 制定一个 失效时长
- 在接口调用时,根据 当前时间 对比 登录时间 ,看是否超过了 时效时长
- 如果未超过,则正常进行后续操作
- 如果超过,则进行 退出登录 操作
# 代码实现:
创建 utils/auth.js
文件,并写入以下代码:
import { TIME_STAMP, TOKEN_TIMEOUT_VALUE } from '@/constant'
import { setItem, getItem } from '@/utils/storage'
/**
* 获取时间戳
*/
export function getTimeStamp() {
return getItem(TIME_STAMP)
}
/**
* 设置时间戳
*/
export function setTimeStamp() {
setItem(TIME_STAMP, Date.now())
}
/**
* 是否超时
*/
export function isCheckTimeout() {
// 当前时间戳
var currentTime = Date.now()
// 缓存时间戳
var timeStamp = getTimeStamp()
return currentTime - timeStamp > TOKEN_TIMEOUT_VALUE
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在 constant
中声明对应常量:
// token 时间戳
export const TIME_STAMP = 'timeStamp'
// 超时时长(毫秒) 两小时
export const TOKEN_TIMEOUT_VALUE = 2 * 3600 * 1000
2
3
4
在用户登录成功后设置时间,到 store/user.js
的 login
中:
import { setTimeStamp } from '@/utils/auth'
login(context, userInfo) {
...
return new Promise((resolve, reject) => {
...
.then(data => {
...
// 保存登录时间
setTimeStamp()
resolve()
})
})
},
2
3
4
5
6
7
8
9
10
11
12
13
14
在 utils/request
对应的请求拦截器中进行 主动介入
import { isCheckTimeout } from '@/utils/auth'
if (store.getters.token) {
if (isCheckTimeout()) {
// 登出操作
store.dispatch('user/logout')
return Promise.reject(new Error('token 失效'))
}
...
}
2
3
4
5
6
7
8
9
10
# 被动退出解决方案之被动解决
背景:
token
过期- 单用户登录
token
过期
token
本身就是具备时效的,在服务端生成token
时就已确定。而所谓的token
过期指:服务端生成的token
超过 服务端指定时效 的过程
单用户登录
当用户 A 登录之后,
token
过期之前。用户 A 的账号在其他的设备中进行了二次登录,导致第一次登录的 A 账号被 “顶下来” 的过程。同一账户仅可以在一个设备中保持在线状态
以上两种情况,都在服务端进行判断的,但对于前端而言是 服务端通知前端的一个过程。
# 实现步骤
服务端返回数据时,会通过特定的状态码通知前端
当前端接收到特定状态码时,即表示遇到了特定状态:
token
时效 或 单用户登录此时进行 退出登录 处理
但这里需要注意,因为咱课程的特性,同一个账号需要在多个设备中使用,所以说此时将不会指定 单用户登录 的状态码,仅有
token
失效 状态码。之后当大家需要到 单用户登录 时,只需要增加一个状态码判断即可。
# 代码实现:
在 utils/request
的响应拦截器中,增加以下逻辑:
// 响应拦截器
service.interceptors.response.use(
response => {
...
},
error => {
// 处理 token 超时问题
if (
error.response &&
error.response.data &&
error.response.data.code === 401
) {
// token超时
store.dispatch('user/logout')
}
ElMessage.error(error.message) // 提示错误信息
return Promise.reject(error)
}
)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19