V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Totato5749
V2EX  ›  Android

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

  •  
  •   Totato5749 · 2016-06-14 15:13:54 +08:00 · 17012 次点击
    这是一个创建于 3109 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    token 过期有以下几个原因:

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

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

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

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

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


    这么写可以吗? 有哪些糟点?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2827 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:59 · PVG 22:59 · LAX 06:59 · JFK 09:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.