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

服务端一般怎么处理 token?

  •  
  •   AscenZ · 2017-04-01 11:49:37 +08:00 · 7691 次点击
    这是一个创建于 936 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前一直在写 iOS ,前后端分离,每次请求带上 token 就行了。

    现在想写一下后端,想问一下一般是怎么处理 token 的?

    用户登录的时候根据 userID 加上时间戳 或者 加上一个自定义值 用加密算法生成 token 之后,

    1.存到数据库中(能设置过期时间吗?),每次客户端请求的时候取出来验证

    2.存到 redis 中,设置过期时间,每次客户端请求的时候取出来验证

    3.不存,每次客户端请求的时候根据之前的生成方法再生成一次来验证

    哪种方法成本更低? 或者有更好的方法吗?

    第 1 条附言  ·  2017-04-01 16:44:10 +08:00
    感觉大家的回复。

    和一些后台程序员也讨论了一下,很多都是不存,即用 JWT

    https://jwt.io/

    目前已经有很多语言的库都支持了。
    38 回复  |  直到 2017-04-02 13:23:41 +08:00
        1
    sfwn   2017-04-01 11:54:20 +08:00
    第三种能解释下吗
        2
    chuanwu   2017-04-01 12:03:11 +08:00
    @sfwn 猜测应该是类似 jwt 那种吧。
        3
    AscenZ   2017-04-01 12:10:09 +08:00
    @sfwn
    例如客户端登录后服务器生成 token 之后返回,之后客户端请求的时候带上这个 token ,服务端每次都根据之前生成的方法(例如加上了自定义值,使用了什么加密算法)再生成一次来比较,一样就验证成功
    就是楼上说的 JWT ,我也是刚接触
        4
    horsley   2017-04-01 12:18:51 +08:00
    我实现过的是不存,仅验证
        5
    lurenw   2017-04-01 12:22:33 +08:00
    有的数据库是支持设置过期时间的, 1 和 2 一个意思。
        6
    ytmsdy   2017-04-01 12:23:03 +08:00
    一般都是 token+用户名,在数据库中查询 token 对应的用户名。
    如果用户名和客户端发送的一致则继续正常的访问。
    如果不一致丢 401 错误。
        7
    jedrek   2017-04-01 12:36:10 +08:00   ♥ 1
    都不需要存,对用户 ID 和过期时间戳签名即可得到 token 。
    token 不应存私密的信息,所以不需要加密。而是要签名,防篡改。
        8
    klesh   2017-04-01 12:40:13 +08:00 via Android   ♥ 1
    看 jwt 规范你就明白了。
    一般不需要存,但若要实现 revoke 之类就要存储
        9
    jedrek   2017-04-01 12:46:33 +08:00   ♥ 1
    @klesh 比如修改密码后,需要吊销之前的 token ,所以用户 ID 和过期时间戳之外,再加一个值,这个值可存在缓存中,每次请求先对 token 验证,通过后再拿缓存中的值与 token 中的比较
        10
    byfar   2017-04-01 12:47:14 +08:00
    登录成功后生成一个 token 存表存 redis 都行

    一个 token 对应一个 uid
        11
    avichen   2017-04-01 13:23:06 +08:00
    JWT : Json web Token ,可以去了解一下
        12
    klesh   2017-04-01 13:49:42 +08:00
    @jedrek

    这样的流程需要进行, 1 。解码 token , 2 。验证 token , 3 。把值与缓存比对。
    我认为不需要所谓的“值”,直接把 token 放到缓存中,利用 set 进行比对是很快的,都不需要解码和验证 token 。同时, token 一定要设定有效期,如一周,这样缓存中只需存最近一周内被 revoke 的 token ,在空间和时间上更合理。如果用户不喜欢每七天登录一次,可以在客户端设计一套自动 refresh token 的机制。
        13
    Ouyangan   2017-04-01 14:02:16 +08:00
    直接用 session 吧 ,自己搞来搞去最后都搞成了 session
        14
    sampeng   2017-04-01 14:11:26 +08:00
    一直很不理解 token 的使用场景。。。搞来搞去不就是个 session 么?
    完整实现了 http 协议的哪个不能支持 session ?还是因为懒
        15
    SourceMan   2017-04-01 14:14:16 +08:00
    2
        16
    jimzhong   2017-04-01 14:15:19 +08:00
    @sampeng 主要是因为 session 依赖于 cookie 吧
        17
    jedrek   2017-04-01 14:26:42 +08:00   ♥ 1
    不用 JWT , token 是这样的结构:签名后的字符串-用户 ID-指纹,共三段,每段中划线分隔.由于要谈到 token 吊销需要存储的问题,所以这里可以不需要存时间戳了。

    当注册 /登录成功后:
    1. 指定一个指纹,任意值都可以,只要这个值对这个用户没有使用过即可。
    2. 将指纹和用户 ID 拼起来并签名,组成 签名后的字符串-用户 ID-指纹 这样结构的 token 。
    3. 将用户 ID 与指纹对应起来放到缓存中,并且设置缓存过期时间,这个时间就是 token 有效期。
    4. 将 token 返回给客户端。

    当用户再次请求时:
    1. 将 token 中的用户 ID 和指纹再签名(通过服务端私钥),比对提交的 token 签名后的字符串 就可将篡改或伪造的 token 过滤掉了(或许这一步有更好的实现方式)。
    2. 过了上一步,仍然无法确定 token 是否已被吊销。获取缓存中的指纹与提交的 token 的指纹比对,若缓存中取不到指纹值(缓存已设置过有效期期)或缓存中的指纹与 token 的指纹值不相符,就说明这个 token 被吊销了。
    3. 通过了上面两步,表示这个请求是已认证了的。
        18
    jedrek   2017-04-01 14:27:23 +08:00
    @klesh 忘了
        19
    jarlyyn   2017-04-01 14:29:48 +08:00
    我是做了一个 cachegroup.
    前端 redis 热数据,后端 mysql 全部数据。

    另外, token 不是应该随机生成的吗?
        20
    ppmoon   2017-04-01 14:31:45 +08:00   ♥ 1
    推荐楼上说的 JWT ,这种方式比较简单,如果应用安全级别不高很实用。客户端存一份 token ,存哪里都行,然后每次需要权限操作的时候就带着 token 去请求。后端接到请求的时候就验证一下。 JWT 把状态放在客户端,后台压力小,要是使用 session 还需要占用服务器资源。 session 多了还需要去管理 session
        21
    jarlyyn   2017-04-01 14:34:10 +08:00
    @sampeng

    Session 一般(除了 cookie based session )就是基于 token 的一种具体实现啊。

    不就是把 token 存在对应的 cookie 里么……
        22
    kulove   2017-04-01 14:35:37 +08:00
    aes 加密用户 id ,过期时间 每次请求解密判断是否过期
        23
    phx13ye   2017-04-01 15:00:38 +08:00
    如果 jwt 也要存,不就变成 session 了么,后续又会遇到一对分布式 session 要处理的问题,这样好处在哪?求详细说明
        24
    avichen   2017-04-01 15:20:12 +08:00
    @phx13ye #23 jwt 在 local 本地存储,每次请求带过去,让 server 校验,不会存在分布式的问题
        25
    phx13ye   2017-04-01 16:18:23 +08:00
    @avichen 想把 JWT 作为 app 端和网页端登录凭证。那么 logout 的时候,一般也只是客户端删掉 JWT 吗?

    假如在 payload 里设置过期时间 60 秒,如何防止在 59 秒还可以成功请求, 61 秒就要求用户重新登录的情况呢? JWT 有自带的机制去处理吗
        26
    vjnjc   2017-04-01 16:27:23 +08:00
    1 , 2 看起来一样。 1 的话存的时候带过期时间呀。
    3 的话看起来不安全,通过逻辑生成总是有漏洞(/规律)
        27
    avichen   2017-04-01 16:30:02 +08:00   ♥ 1
    @phx13ye #25 logout 时可以采用你说的删除 token ,另外 59 秒的问题,貌似没有解决办法,这一秒请求完了,下一秒再请求,它不就过期了嘛,对你的业务影响会很大吗?
        28
    behappy   2017-04-01 17:07:13 +08:00
    @jarlyyn
    请教一个问题,假如我先打开网页 A ,这时候服务器在努力运算生成 token,但是出于某种原因卡住了。然后我又开了个新标签仍然打开网页 A, 然而这次服务端生成 token 后很快就返回了然后写入 cookie 成功了。然后前一次的 token 慢悠悠的返回了,把第二次的 token 覆盖掉了。这种情况该咋整
        29
    Ouyangan   2017-04-01 17:11:49 +08:00
    @behappy jwt 的话没有影响 , token 合法就成了 , 因为服务器根本就没存 token.
        30
    jarlyyn   2017-04-01 17:27:09 +08:00
    @behappy

    你的 token 是存在 cookie 的吗?

    这是标准的 session 啊。

    应该是最后一个 token 生效。
        31
    CareiOS   2017-04-01 17:32:45 +08:00
    @sfwn 就是服务器用对称加密,将数据加密得到一个 string ,然后返回给 client, 每次 client 请求都带上这个 string, 服务器收到后解密,判断是否过期等....
        32
    asen477   2017-04-01 17:47:41 +08:00
    一般 app 端存 token 不会做短期的时间验证
    一般存在本地都会很长时间。
        33
    behappy   2017-04-01 17:49:56 +08:00
    @jarlyyn 好的
        34
    chuanwu   2017-04-01 17:54:50 +08:00
    @phx13ye 对于这种场景, jwt 确实没有好的方式解决,这时候可以依赖服务端来做啊。
        35
    phx13ye   2017-04-01 19:40:16 +08:00 via iPhone
    @avichen 想知道有没有最佳实践
        36
    phx13ye   2017-04-01 19:44:08 +08:00 via iPhone
    @chuanwu 嗯,之前的做法是在记录一下心跳时间,导致服务端要记录。也许可以在快要过期时重新分配一个 token 更好
        37
    yankbytes   2017-04-02 01:57:57 +08:00 via iPhone
    @behappy 再去拿个 token ?一般来说除了 accesstoken 还会有 refreshtoken
        38
    sutra   2017-04-02 13:23:41 +08:00
    spring-session
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3473 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 29ms · UTC 04:35 · PVG 12:35 · LAX 21:35 · JFK 00:35
    ♥ Do have faith in what you're doing.