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

询问服务器 token 的实现方案

  •  
  •   xx314327475 · 2015-07-02 15:48:38 +08:00 · 11275 次点击
    这是一个创建于 3193 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前笔者做了一款iOS的App,需要访问服务器资源,当App登录以后,服务器端验证通过后,会返回一个访问token,用于校验后序的api访问操作,App以后所有的请求都会带上这个token参数,现在想问下,这个token如何实现?

    有朋友建议我使用session的session id来实现这个token,但是session销毁后,用户就必须重新登录了,你们有什么好的办法么?

    第 1 条附言  ·  2015-07-02 17:27:23 +08:00
    谢谢各位,已经想明白了~~
    56 条回复    2015-07-03 17:40:12 +08:00
    q84629462
        1
    q84629462  
       2015-07-02 15:52:58 +08:00 via Android   ❤️ 1
    不销毁session不就可以了吗
    xx314327475
        2
    xx314327475  
    OP
       2015-07-02 15:56:23 +08:00
    @q84629462 不销毁session服务器内存可能吃不消,而且我这个服务器在没有访问的时候会自动休眠,session也会被销毁.
    xx314327475
        3
    xx314327475  
    OP
       2015-07-02 15:56:59 +08:00
    @q84629462 可以不用token么?
    xx314327475
        4
    xx314327475  
    OP
       2015-07-02 15:57:30 +08:00
    @q84629462 可以不用session么?
    ipconfiger
        5
    ipconfiger  
       2015-07-02 15:59:09 +08:00
    直接用oAuth2的方案不行么?
    hahasong
        6
    hahasong  
       2015-07-02 16:00:28 +08:00
    已经登录了为何还要带token识别状态,在服务端根据用户身份处理就好了
    q84629462
        7
    q84629462  
       2015-07-02 16:01:35 +08:00 via Android
    @xx314327475 那就放数据库呗,不就保存一个字符串而已
    BuilderQiu
        8
    BuilderQiu  
       2015-07-02 16:01:41 +08:00
    用户主要信息ID之类的+过期时间+balabala+...
    加密生成token,客户端保存

    请求时过滤器解密验证
    xx314327475
        9
    xx314327475  
    OP
       2015-07-02 16:01:44 +08:00
    @ipconfiger oAuth2是不是有些过于复杂了?
    xx314327475
        10
    xx314327475  
    OP
       2015-07-02 16:04:07 +08:00
    @hahasong 因为http是无状态的,token是用来校验用户权限的,告诉服务器这用户已经登录了,不用再校验了,具体用他的原因主要是防止其他人盗用api,而且每次app请求都不能带上用户名和密码吧?
    xx314327475
        11
    xx314327475  
    OP
       2015-07-02 16:04:56 +08:00
    @q84629462 每次请求都去数据库查一次么?放内存中如何管理呢?什么时候销毁呢?
    xx314327475
        12
    xx314327475  
    OP
       2015-07-02 16:05:38 +08:00
    @BuilderQiu 客户端保存我是清楚的,token如何生成我也是明白的,我不明白是服务器是如何保存用户的登录状态.
    glasslion
        13
    glasslion  
       2015-07-02 16:11:22 +08:00
    @xx314327475 一个session才多少大小,就能把你们服务器内存给吃光了?
    xx314327475
        14
    xx314327475  
    OP
       2015-07-02 16:12:31 +08:00
    @glasslion 不是怕吃光,但是这种实现感觉总是不好的
    billlee
        15
    billlee  
       2015-07-02 16:12:44 +08:00
    我自己做的小项目,试过用 redis 保存 session, 感觉还不错。可以设置过期时间,到期 redis 会自动销毁。
    q84629462
        16
    q84629462  
       2015-07-02 16:13:06 +08:00 via Android
    token嘛,多数一个月,有的一年,要看你的账号使用条件,例如异地ip立即销毁,一段时间内多个IP使用立即销毁之类的
    xx314327475
        17
    xx314327475  
    OP
       2015-07-02 16:13:53 +08:00
    @billlee 可是你怎么知道什么时候销毁session呢?session销毁了,我app的用户怎么办?
    xx314327475
        18
    xx314327475  
    OP
       2015-07-02 16:15:03 +08:00
    @q84629462 你的意思是这个不用服务器的session id来做,自己在服务器实现下,然后根据你所说的算法,来用程序销毁
    q84629462
        19
    q84629462  
       2015-07-02 16:17:54 +08:00 via Android
    @xx314327475 token不就为了让用户一次登录长时间免登录么,当然要有安全机制,网络传输被抓包别人就可以用了,毕竟是明文的玩意
    hahasong
        20
    hahasong  
       2015-07-02 16:18:28 +08:00
    @xx314327475 登录态跟web一样,登录完了写sesseion 和 cookie 不就完了,每次请求带上cookie
    nisnaker
        21
    nisnaker  
       2015-07-02 16:20:05 +08:00   ❤️ 1
    登录之后在服务端用当前用户的唯一id和时间戳做加密,加密的结果作为token返回给客户端。
    之后每次请求带上这个token,服务端解密,如果能成功解密而且时间没有过期,就认为登录成功。
    至于其他业务建议跟这个token解耦,该查询的查询,该缓存的缓存,不要把这个token当做session来用(存一些临时的东西神马的)。
    xgfan
        22
    xgfan  
       2015-07-02 16:20:19 +08:00   ❤️ 1
    放内存,放token和激活时间,每次访问API都刷新一下token的激活时间。超时的时候删掉就好了。
    q84629462
        23
    q84629462  
       2015-07-02 16:21:20 +08:00 via Android
    token放哪看你服务器条件,内存大的放内存,内存不够大的就只能硬盘存储,不就只有这两种存档方式嘛
    你也可以做个折中,活跃度高的token放内存,一段时间内不活跃的就扔硬盘
    billlee
        24
    billlee  
       2015-07-02 16:22:03 +08:00
    @xx314327475 这就看你的需求了。如果是长期的会话, 就按照 @q84629462 说的处理。如果是单次使用的会话,我是连续 20 分钟没有通信活动的情况下销毁。
    q84629462
        25
    q84629462  
       2015-07-02 16:28:00 +08:00 via Android
    @billlee app用肯定是长期的了,支付宝app也没有一天不用就要登录一次的变态要求,楼主做的app应该不会比支付宝还危险吧
    BuilderQiu
        26
    BuilderQiu  
       2015-07-02 16:31:32 +08:00
    @xx314327475
    都明白了还需要保存登陆状态么。

    例如Java:
    过滤器解析合法的,往ThreadLocal里保存用户信息就完了。
    其他用的地方直接去取。
    处理结束,清除ThreadLocal。
    glasslion
        27
    glasslion  
       2015-07-02 16:38:47 +08:00
    @xx314327475 有毛不好的。 如果你们的服务器连session也不用的话,倒是没有必要单独为 token去破坏 server 的无状态性 , 既然都用了 session, 把token存内存/redis/数据库里能有啥坏处?
    xx314327475
        28
    xx314327475  
    OP
       2015-07-02 16:40:24 +08:00
    @q84629462 谁说要用明文了?
    xx314327475
        29
    xx314327475  
    OP
       2015-07-02 16:41:26 +08:00
    @hahasong cookie里面保存着 session id,然后通过session id 在服务器找回之前的session,但是session我要让他多久过期好呢?
    xx314327475
        30
    xx314327475  
    OP
       2015-07-02 16:46:37 +08:00
    @glasslion
    @q84629462

    那我这个session默认销毁的周期是多长时间呢?难道是永不销毁?
    garfeildma
        31
    garfeildma  
       2015-07-02 16:47:37 +08:00
    建议直接oauth吧,虽然复杂点,但是都有现成的实现,拿来用就好
    xx314327475
        32
    xx314327475  
    OP
       2015-07-02 16:47:48 +08:00
    @billlee 20分钟用户没用就销毁,然后21分钟用户使用了,我让用户重新登陆么?
    hahasong
        33
    hahasong  
       2015-07-02 16:47:49 +08:00   ❤️ 1
    @xx314327475 对,web认证就是这样的。过期时间,那要看你app的设计需求了,如果是强安全的,像银行,证券类,每次放几分钟就超时的就设短一点。如果是聊天社交类的,你可以设一个月或者2周。每请求一次,就重设过期时间
    xx314327475
        34
    xx314327475  
    OP
       2015-07-02 16:48:33 +08:00
    @garfeildma 您说的是oauth 还是 oauth 2.0
    xx314327475
        35
    xx314327475  
    OP
       2015-07-02 16:49:35 +08:00
    @glasslion 问题是session默认生命周期存活多久?
    anubiskong
        36
    anubiskong  
       2015-07-02 16:49:35 +08:00
    session存数据库里面, nodejs+mongodb很容易实现, 其他的后端不知道
    xx314327475
        37
    xx314327475  
    OP
       2015-07-02 16:50:45 +08:00
    @hahasong 感谢!
    zjmdp
        38
    zjmdp  
       2015-07-02 16:53:32 +08:00   ❤️ 1
    @nisnaker 同意这种做法,用户唯一id可使用设备相关的id,ios的可以使用:[[[UIDevice currentDevice] identifierForVendor] UUIDString]
    hahasong
        39
    hahasong  
       2015-07-02 16:54:22 +08:00   ❤️ 1
    @xx314327475 如果用户量不大,几十万以下的,可以用后台语言自带的session管理,比如php是用文件的形式。如果用户量比较大,对性能要求比较高。就开个redis当永久缓存用。每次放进去的时候设一下过期时间,到期会自动删除。或者用户退出登录就马上删除。业务场景都是这么用的
    nisnaker
        40
    nisnaker  
       2015-07-02 17:19:05 +08:00
    @zjmdp 这个id最好还是db里的主键,不然用户卖肾换手机咋办……
    xx314327475
        41
    xx314327475  
    OP
       2015-07-02 17:22:14 +08:00
    @nisnaker 😄
    nisnaker
        42
    nisnaker  
       2015-07-02 17:27:45 +08:00   ❤️ 1
    @xx314327475 其实你问的问题就是这个token怎么办,如果做成加解密的话服务端就什么都不用存。
    至于这个过期时间,就是当前的时间戳减去token里存的时间戳,要不要判定为过期完全在服务器端控制,方便优化。
    而且这个多久过期也不用在这里讨论,看你的具体业务,你可以设成1年有效,大不了app跟支付宝一样做下手势验证;或者5分钟过期,过期之后自动再次登录重新获取token以免用户体验太差。
    zyx89513
        44
    zyx89513  
       2015-07-02 19:37:14 +08:00
    存在数据库, 用 memcache 缓存. 直接存到 redis 也可以
    zhuangzhuang1988
        45
    zhuangzhuang1988  
       2015-07-02 19:51:17 +08:00   ❤️ 1
    用这个库即可 http://pythonhosted.org/itsdangerous/ 也就是@BuilderQiu 的解决方案, 具体在http://book.douban.com/subject/26274202/ 中第14章有. 另外还可以用于邮件验证
    jedrek
        46
    jedrek  
       2015-07-02 20:11:50 +08:00   ❤️ 1
    @BuilderQiu @nisnaker @hahasong @xx314327475
    若认证信息不存储的话,会有些问题。
    一个用户有两个设备,在其中一个设备上改掉密码,另一个设备的token如何失效?
    换种说法,token泄露了,我改密码后,如何让泄漏后的token失效?
    ClearGC
        47
    ClearGC  
       2015-07-02 20:26:23 +08:00 via Android   ❤️ 1
    @jedrek 修改密码时清除该用户在后台(内存、数据库等)的token记录。
    jedrek
        48
    jedrek  
       2015-07-02 20:34:16 +08:00   ❤️ 1
    @ClearGC 是的,认证信息还是得存储才行的
    zhujinlong
        49
    zhujinlong  
       2015-07-02 21:04:50 +08:00   ❤️ 1
    服务端放内存或redis或存db,客户端放headers
    qianlifeng
        50
    qianlifeng  
       2015-07-02 21:15:04 +08:00
    jsob web token
    qianlifeng
        51
    qianlifeng  
       2015-07-02 21:15:15 +08:00   ❤️ 1
    json web token http://jwt.io/
    freeznet
        52
    freeznet  
       2015-07-02 21:18:41 +08:00   ❤️ 1
    bkmi
        53
    bkmi  
       2015-07-02 21:36:04 +08:00   ❤️ 1
    我们用UUID当token,失效机制大概就像楼上说的,登录重新生成,过期失效,修改密码失效,还有些安全规则失效
    nisnaker
        54
    nisnaker  
       2015-07-02 21:47:44 +08:00
    @jedrek 服务端记住这个改密码的时间点,早于这个点的token失效。
    Comdex
        55
    Comdex  
       2015-07-03 12:39:08 +08:00   ❤️ 1
    @nisnaker
    @q84629462
    @nisnaker
    @hahasong 新手能请问一下为了防止重放攻击什么的,貌似要用到什么签名,那个签名是怎么生成的,服务器端又怎样验证的,怎么与token一起使用?谢谢
    aftereclipse
        56
    aftereclipse  
       2015-07-03 17:40:12 +08:00   ❤️ 1
    token放redis和数据库 登录过程采用https或者自定义的加密方式,返回token+过期时间给客户端 。后续所有api调用都校验token。这样分布式部署应用的时候就无需考虑session问题,所有服务器统一从redis中获取校验token就好了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2820 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:42 · PVG 22:42 · LAX 07:42 · JFK 10:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.