求教, Android 如何实现 Token 过期后重新获取并重新进行之前的操作

2016-06-14 15:13:54 +08:00
 Totato5749

公司的项目,用户在客户端登陆后后台会给用户一个 token ,以后每次执行与用户身份有关的操作都需要向服务器带上这个 token,这个 token 在一定时间后失效,这时进行与用户身份有关的操作时会返回 token 过期错误提示。

之前我在处理这个问题时,遇到操作返回 token 过期错误,我会让用户强制重新登录。不过这个处理对用户来说体验很差,基本相当于每天都要重新登录。

token 过期有以下几个原因:

  1. token 时间到期
  2. 用户在其他设备登录,原来设备中的 token 就会过期
  3. 其他异常等

我想要实现的功能是: 在某次网络操作时,当服务器返回 token 过期错误后,如何实现重新获取 token 后再次尝试之前的网络操作,不让用户察觉到中间的断裂感。

求各位大侠指教,小弟跪谢

17012 次点击
所在节点    Android
14 条回复
Ouyangan
2016-06-14 15:22:52 +08:00
那就自动帮用户登录一次 .
Totato5749
2016-06-14 15:24:01 +08:00
@Ouyangan
嗯,重点不是我如何再次获取 token ,而是重新获取到 token 后重复 token 过期前的那次网络操作。
cxe2v
2016-06-14 15:37:32 +08:00
生成 token 的时候把 token 的过期时间记下来,在过期时间后就再去获取新的 token
fds
2016-06-14 15:47:49 +08:00
把操作记录下来呗……
Totato5749
2016-06-14 15:52:49 +08:00
@cxe2v
问题在于有些 token 过期的原因并不是单纯的因为 token 到期,这样判断是不准确的
eminemcola
2016-06-14 16:06:55 +08:00
当返回 token 过期错误时,在 onError 中重新做获取 token 请求,再在获取成功的 callback 中重复用户过期前的操作。这中间的错误提示不显示给用户,对用户来说就是等得更久了点吧。应该可以避免察觉到你所说的断裂感?
hsj1992
2016-06-14 16:51:24 +08:00
@Totato5749
@cxe2v 指的是对应 [用户只是单纯的在同一台设备上使用到 token 到期] 的情况,这应该是“ token 到期”的大头。
撕裂感是因为“出错——>处理”产生的时间,那么,不能从源头“减少 token 到期错误”入手么?
magicdawn
2016-06-14 17:03:26 +08:00
@Ouyangan

怎么帮登录? 存密码?
Ouyangan
2016-06-14 17:35:04 +08:00
@magicdawn 用户登录的时候你把 usename,password 存储下来 ,token 无效的时候,自己帮用户提交一次登录,根据服务器返回的信息判断 token 是否有效,然后进行下一步操作.
tinyproxy
2016-06-14 18:19:11 +08:00
1. 让服务器给 refresh token ,用来获取新的 token ,不然就让后端把 ttl 弄长一点。
2. 你们啥业务这么容易登录过期啊,没啥要紧的东西后端调整 ttl 也就几分钟的事情,你们要业务非常重要,那你这种尝试自动提交账号密码登录简直就是作死。
3. 说存账号密码的,从安全性来说这是个下策
tinyproxy
2016-06-14 18:21:27 +08:00
至于你说的其他设备登录,当前设备 token 过期,也让后端把单点登录限制去了,不同意让产品跟他撕逼,你也用不着管,锅一下子就甩干净了
ki41foo
2016-06-14 22:31:18 +08:00
如果 token 只能通过登录获取的话,只能存帐号密码自动登录了啊。
ifane
2016-06-15 08:25:36 +08:00
我做模拟登录教务系统的时候,cookie 会过期,解决办法我就只能要做啥操作前,判断 cookie 有没有过期,如果过期了就只能重新模拟登录了
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


这么写可以吗? 有哪些糟点?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/285649

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX