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

关于微服务架构落地的一些疑问

  •  
  •   sha851092391 · 2020-08-25 17:39:33 +08:00 · 4606 次点击
    这是一个创建于 1312 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Q1: Gateway 使用 JWT 作为 Token 的解决方案中,每个业务服务中如何做授权校验?

    • 一种方式是 JWT 的 Payload 中包含了“角色”或者“权限”等信息,但是 Token 会变大。
    • 另一种方式是业务服务通过 JWT 再去请求一次用户服务拿到“角色”或者“权限”等信息,但是网络请求会增加。

    Q2: 一般是 Gateway 使用的服务名的路由策略把所有注册的服务的所有接口都暴露出去,就会把类似“通过用户 ID 获取用户信息”这类的基础接口服务都暴露出去,一般这种场景如何去做?

    • 现在使用聚合服务,网关只暴露聚合服务出去即可,但是就会出现很多非常薄的一层聚合服务。

    Q3:定时任务、MQ 消费者、异步任务等任务去调用其他业务服务时,因为其他业务服务需要 token,像这种场景如何处理?

    • 现在我们会生成一个临时的 token 用作该类场景的服务调用。
    第 1 条附言  ·  2020-08-27 11:21:08 +08:00

    整理了下这边的方案,大伙帮忙给下给下意见。

    前端
    --------------------
      ^
      |  
     网关         (token认证,只暴露聚合服务,保证基础的接口不被暴露)
    --------------------
     BFF    BFF  (聚合服务,RBAC授权控制)
    --------------------
     ^ ^    ^ ^
    /   \  /   \
    --------------------
    下游原子服务  (无权限 或 oauth2 的 client credentials 做服务间认证)
    
    36 条回复    2020-08-28 17:20:57 +08:00
    imherer
        1
    imherer  
       2020-08-25 17:56:36 +08:00   ❤️ 1
    不要为了微服务而微服务,适当的拆分吧。 感觉有时候拆太细反而不好

    个人愚见

    Q1:我倾向于把角色权限等信息放在 token 里,这样可以减少请求。 但是不知道你的权限信息有多大。你也说了 token 会变大

    Q2:微信或者 QQ 第三方登录类似吧?都是先授权那到 acces_token 然后后面用这个 token 去做别的事

    Q3:是否可以改成签名验证就好了? token 的话先要发一次请求拿到 token,然后才能请求。但你实际上只是为了验证请求的合法性?
    xomix
        2
    xomix  
       2020-08-25 18:11:06 +08:00
    Token 在系统中的作用是令牌,令牌需要验证后确认令牌权限,不同接口权限不应一致,你可以在令牌中存储一些简单的 claim 信息,但是不应该把 policy 的东西存储在令牌里面。
    验证丢下令牌的县令是否具有令牌权限的应当是衙役,而不是在令牌上写着县令权限令牌见令牌就直接执行命令不管扔下令牌的是县令还是胡闹的宋世杰。
    xomix
        3
    xomix  
       2020-08-25 18:13:48 +08:00
    令牌可以有简单的 claim 信息就好像令牌可以写甲乙丙不同刑法,但是丢下令牌的整个过程是否符合执行刑罚的权限是要衙役验证的,不是随时丢令牌就可以执行刑法不是吗?
    ZSeptember
        4
    ZSeptember  
       2020-08-25 18:23:54 +08:00
    Q1:简单鉴权在 gateway 做了,Gateway 鉴权后向后面的服务直接传递 account_id,roles 等 header,这些是可信的。
    Q2:gateway 提供配置功能,服务可配置在 gateway 不暴露某些接口,只允许内部调用
    Q3:内部业务服务调用走内部服务调用鉴权,跟用户请求鉴权不一样。内部服务,一般是有比较高的权限,能访问所有用户数据。
    zhazi
        5
    zhazi  
       2020-08-25 18:43:38 +08:00
    oauth2.0 就可以解决资源鉴权问题。
    sha851092391
        6
    sha851092391  
    OP
       2020-08-25 19:23:00 +08:00 via iPhone
    @xomix 这个抽象理解的很好,token 仅做认证,授权应该业务服务做准入实现。但是这也造成在调用链路中每个参与者都需要去获得用户权限并验证的问题。
    sha851092391
        7
    sha851092391  
    OP
       2020-08-25 19:27:07 +08:00 via iPhone
    @imherer 谢谢回复,现在已经是 oauth2 授权模式了。还有签名仅用做数据的有效性校验,跟认证授权应该是不一样的。去请求 token 也可以,但是你通过哪个用户信息去请求,因为这里是非用户发起的。
    sha851092391
        8
    sha851092391  
    OP
       2020-08-25 19:28:12 +08:00 via iPhone
    @zhazi 认证已经使用了 oauth2 了,但是 rabc 的授权还是做的不够优雅。
    sha851092391
        9
    sha851092391  
    OP
       2020-08-25 19:38:00 +08:00 via iPhone
    @ZSeptember

    a1:这种方式考虑过,但是由于服务与服务之间调用不走 gateway 的,所以这种从服务内安全性和我 q3 问题还是本地调试都需要手动填写相关授权信息。

    a2:是的,需要定制网关,但是就需要成本去维护那些接口不被外部调用,这里面会存在遗漏。

    a3:但是被调用的服务其实用户也会用到,定时任务也会用到,所以没法很好的区分两种授权方式
    Leigg
        10
    Leigg  
       2020-08-25 20:56:09 +08:00 via Android
    定时任务是内部调用,还要搞临时 token 不麻烦?给调用者一个不过期 token,只能调用对应接口不就好了。
    linvon
        11
    linvon  
       2020-08-25 21:10:23 +08:00
    我感觉你这三个问题都出在一个点上啊,就是 Gateway 与 Service 的隔离
    Q1 鉴权在 Gateway 做过就不用再做了,到 Service 的调用都传内部 id 就可以了
    Q2 Gateway 和 Service 分开部署,Service 机器在网络拓扑上仅向 Gateway 环境开放,这样 Service 也不需要担心接口暴露,而 Gateway 只暴露业务接口
    Q3 内部的离线服务调用服务直接调用 Service 就可以了,不需要再鉴权了,当然如果要模拟业务那可能确实需要一个固定 token
    yaming116
        12
    yaming116  
       2020-08-25 21:47:14 +08:00 via iPhone
    内部 rpc,外部才走 http
    Kyle18Tang
        13
    Kyle18Tang  
       2020-08-25 22:36:48 +08:00
    1. 用户信息我们放在 token 里, 不用每次都请求数据库
    2. 异步或者定时任务通过 OAuth 的客户端模式申请 token 然后调用
    paragon
        14
    paragon  
       2020-08-25 23:19:21 +08:00   ❤️ 1
    用户信息在网关获取了就可以透传下去了~
    twl007
        15
    twl007  
       2020-08-25 23:22:21 +08:00 via iPhone
    lihongming
        16
    lihongming  
       2020-08-26 04:11:17 +08:00 via iPhone
    关于 gateway,直接抄一下各大云的功能吧,已经算最佳实践了。不轻不重的,用起来很舒服。
    xuanbg
        17
    xuanbg  
       2020-08-26 07:21:07 +08:00
    Q1: Gateway 使用 JWT 作为 Token 的解决方案中,每个业务服务中如何做授权校验?
    A1:在网关中根据 url 判断用户是否授权。你需要在对角色授权时把操作权限与对应接口的 url 做关联,可能会 1 个操作权限对应多个 url 。

    Q2: 一般是 Gateway 使用的服务名的路由策略把所有注册的服务的所有接口都暴露出去,就会把类似“通过用户 ID 获取用户信息”这类的基础接口服务都暴露出去,一般这种场景如何去做?
    A2:不要使用自增 ID 就没关系了,接口本来就应该暴露出去。

    Q3:定时任务、MQ 消费者、异步任务等任务去调用其他业务服务时,因为其他业务服务需要 token,像这种场景如何处理?
    A3:只在网关鉴权,就不存在这个问题。
    xuanbg
        18
    xuanbg  
       2020-08-26 07:25:15 +08:00
    @xuanbg 补充 A1:token 可以不带任何授权信息,在网关根据用户 ID 和 url 进行鉴权,鉴权过程最简单的做法就是查表。进一步优化就是缓存,但缓存的更新是非常复杂的问题。qps 不高的情况下直接查表就行了。
    yule111222
        19
    yule111222  
       2020-08-26 08:14:20 +08:00
    内部接口加上 @PreAuthorize("#oauth2.hasScope('server')")
    再在 feign 做一个拦截器把客户端模式的 token 带上即可

    另外都用 JWT 了当然把权限信息放到 token 里面
    dyllen
        20
    dyllen  
       2020-08-26 09:50:22 +08:00
    @sha851092391 内部调用你还搞个 oauth2 ?用数据签名就行了,数据签名需要一个密钥的,那个密钥不就是鉴权了,保存好。
    xuanbg
        21
    xuanbg  
       2020-08-26 10:00:03 +08:00
    @yule111222
    >内部接口加上 @PreAuthorize("#oauth2.hasScope('server')")
    >再在 feign 做一个拦截器把客户端模式的 token 带上即可
    >另外都用 JWT 了当然把权限信息放到 token 里面

    楼主有定时任务要调用的时候,就没有 token 。权限信息放 token 里面会使 token 变得非常大。所以楼主才来提问。
    Evilk
        22
    Evilk  
       2020-08-26 11:37:09 +08:00
    我们用不上微服务,只上了 SOA
    sha851092391
        23
    sha851092391  
    OP
       2020-08-26 12:31:38 +08:00
    临时和永久做法都是一样的,关键是 token 需要对应一个用户(现在对应一个叫做“系统用户”的用户),token 做认证,用户信息做授权,所以这种做法感觉不够优雅。
    sha851092391
        24
    sha851092391  
    OP
       2020-08-26 12:43:55 +08:00
    @linvon
    A1:我们有考虑过,token 认证完成后南向的服务请求直接传递 uid,但是授权的问题还是存在每个被调用的服务都要去拿一遍用户的角色以及权限等信息。这里网络请求会变成 2n 次。
    A2:是的,部署没问题。例如“用户服务”里面有很多接口,其中包括“通过用户 ids 批量获取用户信息”等基础接口供其他服务调用。因为 Gateway 直接路由到“用户服务”,就相当于能访问该服务所有的接口。如果要限制,就需要人工声明管理哪些接口是基础的不给外部调用的。这也是我们目前的做法,维护成本太高。
    A3:因为会调用业务服务,所以模拟 token,但是由于 token 是对应用户的,所以这里面需要指定一个“系统用户”去对应 token (默认用户设计)。因为对数据修改需要获取修改人记录日志。
    sha851092391
        25
    sha851092391  
    OP
       2020-08-26 12:44:44 +08:00
    @yaming116 哈哈,这不是协议的问题。
    sha851092391
        26
    sha851092391  
    OP
       2020-08-26 12:46:55 +08:00
    @paragon
    和 @linvon 的 Q1 描述的一样,认证没问题,但是授权的问题还是存在每个被调用的服务都要去拿一遍用户的角色以及权限等信息。这里网络请求会变成 2n 次
    sha851092391
        27
    sha851092391  
    OP
       2020-08-26 12:53:43 +08:00
    @Kyle18Tang
    A1:是的,JWT 自验证就是为了减少获取用户信息的请求。认证没问题,但是每个服务的 RBAC 的授权就还没什么好的解决方案。
    A2:是的,目前类似这么做,但是因为业务服务需要知道当前用户,因此 client credentials 无用户对应所以不太适用。
    sha851092391
        28
    sha851092391  
    OP
       2020-08-26 13:00:32 +08:00
    @Evilk 是的,其实 80%的所谓微服务顶多就算服务化,还没到微服务化的水平。更多的不是为了业务而是为了微服务而微服务。
    sha851092391
        29
    sha851092391  
    OP
       2020-08-26 13:04:39 +08:00
    @lihongming 嗯嗯,网关其实只是一部分。其实很多问题不仅仅在网关,而是服务之间的治理和编排上。
    xomix
        30
    xomix  
       2020-08-26 14:35:43 +08:00
    @sha851092391 这种时候你是搞一个部门审核( policy 整体服务)还是每个衙役单独审核(单独接口内 policy 审核)是你根据自己业务范围和系统承载自己去规划的事情,你也可用来个尚方宝剑( token 直接鉴权)见剑如见圣亲临也不是不行,鱼符和符( hash(查询信息+key)后服务端和客户端的 hash 值比对)也不是不行啊。鉴权这个东西人类社会已经有几千年的历史给你参考,你自己基于自己的实际业务需求选择合适的鉴权方式实现,不要被技术绑死了才好。
    sha851092391
        31
    sha851092391  
    OP
       2020-08-26 14:47:59 +08:00
    @xuanbg
    A1:对的,现在这种方案统一在 gateway 层做 url 级的授权校验。
    A2:非自增也无法保证安全性。因为这种接口其实是拆分后无法 join 表用的基础接口,仅内部调用的。
    A3:就是网关所以需要一个用户 token 才能调用,而且这个 token 必须映射到一个用户上去。
    sha851092391
        32
    sha851092391  
    OP
       2020-08-26 14:49:22 +08:00
    @twl007 好像是 CNCF 孵化的东西,了解看看。
    sha851092391
        33
    sha851092391  
    OP
       2020-08-26 14:59:06 +08:00
    @xomix 整体和单独做认证授权都试过,就是各有各的问题,因为是自己摸索的,所以想了解下有没有更好的实践。token 直接鉴权的方式只适合于 C 端用户权限不负责的情况,但是对于有 RBAC 要求的就不行了。签名部分仅保证传输的安全性,不适合用作用户维度的认证。
    xuanbg
        34
    xuanbg  
       2020-08-26 15:22:51 +08:00
    @sha851092391 #31 这种接口你可以标记为需要授权,这样没权限就调用不了,也就安全了呀。
    第三个问题,你的调用不经过网关,自然不需要验证和鉴权。把身份验证和鉴权放在网关的目的是由网关统一实现,这样服务就不需要实现,服务间调用也就不需要 token 了。
    cloudhuang
        35
    cloudhuang  
       2020-08-28 17:19:59 +08:00
    Q1. 内部服务是裸奔的,Token 不是用在内部服务之间,而是外部 ---> Gateway 这部分的
    cloudhuang
        36
    cloudhuang  
       2020-08-28 17:20:57 +08:00
    Q2. 你都网关了,怎么会存在这个问题
    Q3. 见 Q1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2752 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:10 · PVG 20:10 · LAX 05:10 · JFK 08:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.