询问服务器 token 的实现方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xx314327475
V2EX    Java

询问服务器 token 的实现方案

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

    目前笔者做了一款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 Andoid
    @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来用(存一些临时的东西神马的)。
    6IbA2bj5ip3tK49j
        22
    6IbA2bj5ip3tK49j  
       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
       
    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
        42
    nisnaker  
       2015-07-02 17:27:45 +08:00   1
    @xx314327475 其实你问的问题就是这个token怎么办,如果做成加解密的话服务端就什么都不用存。
    至于这个过期时间,就是当前的时间戳减去token里存的时间戳,要不要判定为过期完全在服务器端控制,方便优化。
    而且这个多久过期也不用在这里讨论,看你的具体业务,你可以设成1年有效,大不了app跟支付宝一样做下手势验证;或者5分钟过期,过期之后自动再次登录重新获取token以免用户体验太差。
    dofaith09
        44
    dofaith09  
       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     Solana     2214 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 16:08 PVG 00:08 LAX 09:08 JFK 12:08
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86