公司的项目,用户在客户端登陆后后台会给用户一个 token ,以后每次执行与用户身份有关的操作都需要向服务器带上这个 token,这个 token 在一定时间后失效,这时进行与用户身份有关的操作时会返回 token 过期错误提示。
之前我在处理这个问题时,遇到操作返回 token 过期错误,我会让用户强制重新登录。不过这个处理对用户来说体验很差,基本相当于每天都要重新登录。
token 过期有以下几个原因:
我想要实现的功能是: 在某次网络操作时,当服务器返回 token 过期错误后,如何实现重新获取 token 后再次尝试之前的网络操作,不让用户察觉到中间的断裂感。
求各位大侠指教,小弟跪谢
1
Ouyangan 2016-06-14 15:22:52 +08:00
那就自动帮用户登录一次 .
|
2
Totato5749 OP @Ouyangan
嗯,重点不是我如何再次获取 token ,而是重新获取到 token 后重复 token 过期前的那次网络操作。 |
3
cxe2v 2016-06-14 15:37:32 +08:00
生成 token 的时候把 token 的过期时间记下来,在过期时间后就再去获取新的 token
|
4
fds 2016-06-14 15:47:49 +08:00
把操作记录下来呗……
|
5
Totato5749 OP @cxe2v
问题在于有些 token 过期的原因并不是单纯的因为 token 到期,这样判断是不准确的 |
6
eminemcola 2016-06-14 16:06:55 +08:00
当返回 token 过期错误时,在 onError 中重新做获取 token 请求,再在获取成功的 callback 中重复用户过期前的操作。这中间的错误提示不显示给用户,对用户来说就是等得更久了点吧。应该可以避免察觉到你所说的断裂感?
|
7
hsj1992 2016-06-14 16:51:24 +08:00
@Totato5749
@cxe2v 指的是对应 [用户只是单纯的在同一台设备上使用到 token 到期] 的情况,这应该是“ token 到期”的大头。 撕裂感是因为“出错——>处理”产生的时间,那么,不能从源头“减少 token 到期错误”入手么? |
9
Ouyangan 2016-06-14 17:35:04 +08:00
@magicdawn 用户登录的时候你把 usename,password 存储下来 ,token 无效的时候,自己帮用户提交一次登录,根据服务器返回的信息判断 token 是否有效,然后进行下一步操作.
|
10
tinyproxy 2016-06-14 18:19:11 +08:00 via iPhone
1. 让服务器给 refresh token ,用来获取新的 token ,不然就让后端把 ttl 弄长一点。
2. 你们啥业务这么容易登录过期啊,没啥要紧的东西后端调整 ttl 也就几分钟的事情,你们要业务非常重要,那你这种尝试自动提交账号密码登录简直就是作死。 3. 说存账号密码的,从安全性来说这是个下策 |
11
tinyproxy 2016-06-14 18:21:27 +08:00 via iPhone
至于你说的其他设备登录,当前设备 token 过期,也让后端把单点登录限制去了,不同意让产品跟他撕逼,你也用不着管,锅一下子就甩干净了
|
12
ki41foo 2016-06-14 22:31:18 +08:00
如果 token 只能通过登录获取的话,只能存帐号密码自动登录了啊。
|
13
ifane 2016-06-15 08:25:36 +08:00
我做模拟登录教务系统的时候,cookie 会过期,解决办法我就只能要做啥操作前,判断 cookie 有没有过期,如果过期了就只能重新模拟登录了
|
14
dearmadman 2016-06-15 10:26:21 +08:00
/**
* 资源获取帮助类,需求: * 1. 常用请求方法 * 2. 自动发送请求头 * 3. 根据状态码进行刷新 token * 4. 刷新 token 后自动请求上次请求内容 * 5. refresh token 过期时提示登录 * 6. 请求方法返回: 状态码 无论 500 还是 0 都会返回 API 内容, token 过期刷新失败直接返回 false */ import storage from './storage.js' import api from './api.js' var http = { $http: {}, config ($http) { this.$http = $http }, http (url, data, options, method) { return this.$http({url: url, method: method, data: data, options: this.autoHeaders(options)}).then((res) => { let body = res.data let status = body.status.code if (status === 401) { return this.refresh().then((res) => { if (res) return this.http(url, data, options, method) return false }) } return body }) }, get (url, data, options) { return this.http(url, data, options, 'GET') }, post (url, data, options) { return this.http(url, data, options, 'POST') }, delete (url, data, options) { return this.http(url, data, options, 'DELETE') }, put (url, data, options) { return this.http(url, data, options, 'PUT') }, refresh () { this.$http.post(api.refresh, null, this.autoHeaders()).then((res) => { if (res.data.status.code === 0) { this.storage.setItem('token', res.data.data.token) return true } return false }) }, autoHeaders (options = {}) { return Object.assign({}, { headers: { Authorization: `Bearer ${storage.getItem('token')}` } }, options) } } export default http 这么写可以吗? 有哪些糟点? |