请教下 Spring Cloud GateWay 网关的鉴权和数据权限, 怎么把 token 转换成用户信息 进入其他服务? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wuzhizuiguo
V2EX    Java

请教下 Spring Cloud GateWay 网关的鉴权和数据权限, 怎么把 token 转换成用户信息 进入其他服务?

  •  
  •   wuzhizuiguo 2020-03-11 15:27:19 +08:00 8144 次点击
    这是一个创建于 2047 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如简单判断有没有权限调用某个接口,我在 gateway 里的 flter 判断一下这个 token 存不存在 redis 中(token -> 用户信息).

    假设现在有个接口是 api.test.com/user/mail/list/ 接口, 需要传入 userId, 获取到这个用户的邮件列表, 怎么让 gateway 转发请求到 user-service 时, 将请求 header 里的 token 转化为 userId,

    userController 里的方法可能是这样的 List<mail> mailList(Long userId);</mail>

    除了网关外其他服务 RPC 调用该接口, 也可以只传入 userId 参数 这样的请问该怎么实现?

    如果是以前的方法,我可能会把这个方法改为 List<mail> mailList(Long usrId,HttpServletRequest request);</mail>

    然后取出 request 中的 token,去 redis 中验证一下, 然后去取出 userId, 但是这样 其他 b.c.d..服务要是 fegin RPC 调用 这个方法时, 就也需要传入 HttpServletRequest/或者 token.

    请教下大佬,Spring Cloud GateWay 网关的鉴权和数据权限该怎么做?

    24 条回复    2022-01-17 19:28:23 +08:00
    gaius
        1
    gaius  
       2020-03-11 15:40:47 +08:00 via Android
    网关调鉴权服务完事把用户信息和权限列表写到 header
    359889741
        2
    359889741  
       2020-03-11 15:41:23 +08:00
    filter 里面读出 userId 来,再往业务服务传递不就行了
    wuzhizuiguo
        3
    wuzhizuiguo  
    OP
       2020-03-11 15:45:51 +08:00
    @gaius 谢谢. 这样在 user-service 里, 对应的方法怎么获取 header 里的写入的信息, 感觉需要在接收的 controller 方法里,添加上 HttpServletRequest 参数, 这样的话 admin 等其他服务也 rpc 调用这个接口 会不会有影响.
    wuzhizuiguo
        4
    wuzhizuiguo  
    OP
       2020-03-11 15:49:48 +08:00
    @359889741 谢谢, 这样感觉可行, 是收经过网关 需要鉴权的的都要 把 token 里的 userId 取出来了. 是指修改请求的参数, 把 userId 放入到 post 的请求 body 里 或者 get 的 param 中吗
    hantsy
        5
    hantsy  
       2020-03-11 16:15:49 +08:00
    也就是说其它里面的 Service 不做安全验证,这样跟裸奔有什么差别。
    hantsy
        6
    hantsy  
       2020-03-11 16:17:58 +08:00
    既然用到 Redis,直接上 Spring Session ( Redis )就好了,Session 里面想丢什么就什么了,一个用户对象也可以。
    hantsy
        7
    hantsy  
       2020-03-11 16:19:31 +08:00
    用 Spring Session+Spring Security 控制安全就可以了,https://github.com/hantsy/spring-microservice-sample
    wuzhizuiguo
        8
    wuzhizuiguo  
    OP
       2020-03-11 16:19:34 +08:00
    @hantsy 这个我看网上是这样的, 其他的 service 不对外开放(放到内网 或者防火墙关了访问端口), 即经过网关校验后 各个服务之间是可以信任的.
    hantsy
        9
    hantsy  
       2020-03-11 16:26:01 +08:00
    不知道这种思维方式哪里来的。。。
    你网关是会对外吧,如果别人能够进入你网关呢?不一样可以再进入里面的服务。
    wuzhizuiguo
        10
    wuzhizuiguo  
    OP
       2020-03-11 16:42:37 +08:00
    @hantsy 是的.. 网关是对外的,如果网关通过了, 那按照我这种,确实是可以按照它的接口权限 访问对应的接口 /服务. 有博客也提到了 spring security . 谢谢, 我也去了解学习下
    yang957862615
        11
    yang957862615  
       2020-03-11 17:09:45 +08:00   1
    实现 GlobalFilter 接口之后使用 ServerWebExchange.getRequest().mutate().header(String headerName, String... headerValues)这个方法就行
    wuzhizuiguo
        12
    wuzhizuiguo  
    OP
       2020-03-11 17:11:52 +08:00
    @yang957862615 谢谢. 那再下个服务里怎么获取到这个 header 里的值呢? 感觉方法里还是需要添加 HttpServletRequest 参数...
    yang957862615
        13
    yang957862615  
       2020-03-11 17:15:45 +08:00
    @wuzhizuiguo springboot 可以在类里面注入 HttpServletRequest 实例就可以不用在方法上加这个参数
    humpy
        14
    humpy  
       2020-03-11 17:19:59 +08:00
    用拿 header 的注解就行了

    @RequestHeader("X-USER-ID") String userId
    caotian
        15
    caotian  
       2020-03-11 17:21:06 +08:00
    如果 JWT 可以满足要求, 不需要用 redis 来存 token, gateway 可以只验证 jwt 是否有效, 然后取出 jwt 里的 userId, 转发请求的时候, 再把 userId 放到 header 里
    wuzhizuiguo
        16
    wuzhizuiguo  
    OP
       2020-03-11 17:25:39 +08:00
    wuzhizuiguo
        17
    wuzhizuiguo  
    OP
       2020-03-11 17:25:54 +08:00
    @humpy 还可以这样.. 第一次看到 谢谢.
    wuzhizuiguo
        18
    wuzhizuiguo  
    OP
       2020-03-11 17:27:03 +08:00
    @caotian 谢谢. 是的, jwt token 也可以.
    rykinia
        19
    rykinia  
       2020-03-12 09:22:29 +08:00
    @hantsy gateway 设置规则,让对外的接口为 /api/**。比如实际的接口是 /user,那么外网调用的 URI 则应该是 /api/user,然后 gateway 转发,这样外网应该没法直接通过 /user 访问吧
    wuzhizuiguo
        20
    wuzhizuiguo  
    OP
       2020-03-12 10:44:05 +08:00
    @humpy @RequestHeader("X-USER-ID") String userId 这个单纯请求是可以的. 但是其他服务 rpc 调用这个接口怎么办?
    @PostMapping(value = "/list")
    public Result list(@RequestHeader(value = "X-USER-ID", required = false) Long userId);
    RPC 方法:
    @PostMapping(value = "/user/mail/list")
    public Result mailList(@RequestParam("userId") Long userId);

    rcp 调用方法里里面的 userId,没有成功传入到 user-service,因为没有 header
    wuzhizuiguo
        21
    wuzhizuiguo  
    OP
       2020-03-12 14:51:09 +08:00
    @yang957862615 这个方法 重写请求头 header 的时候, 需要重新 build 一下,不能直接取出来写入. http://lhyd.top/?p=312761
    //向 headers 中放文件,记得 build
    ServerHttpRequest host = exchange.getRequest().mutate().header("a", "888").build();
    //将现在的 request 变成 change 对象
    ServerWebExchange build = exchange.mutate().request(host).build();
    return chain.filter(build);
    wuzhizuiguo
        22
    wuzhizuiguo  
    OP
       2020-03-20 16:15:58 +08:00
    头晕. 暂时放弃了.
    选用 将 token(存 redis) 或者 JWT token , 在 tokenFilter(继承 GlobalFilter)中放入 header 之中(jwt 参照 https://blog.csdn.net/CrazyLai1996/article/details/86430457)

    然后取本人的数据信息,则使用 @RequestHeader("X-USER-ID") String userId 这种形式去取数据,

    那么如果权限高一点的(例如管理员), 那么 RPC 调用其他用户的邮件列表, 可以使用如下方法

    用户访问自己的:
    @PostMapping("/mail/list")
    public Result x(@RequestHeader(value = "auth-userId",required = false)Long authUserId){
    return mailService.list(authUserId);
    }

    用户访问别人的
    @PostMapping("/mail/list/{userId}")
    public Result maillist(@PathVariable("userId") Long userId){
    return mailService.list(userId);
    }

    RPC 方法
    @PostMapping("/user/test/mail/list/{userId}")
    public Result mm(@PathVariable("userId")Long userId);

    这个 RPC 方法能不能调用, 还是需要 更上面一层的 token 来区分的, 例如传的 userId 能不能不是他本人的, 需要配合 role /permission, 来决定.

    即: 这种可能是, /admin/user/list , 然后可以传入 userId 参数, 加上自己的 header 中的 token,来决定 给 rpc 方法中传递的 userId 到底是直接的,还是别人的.

    在这个问题中,我最大的困扰是, 怎么将 token 背后的用户信息良好的传递到各个服务中去,
    我觉得比较麻烦,但是可行的是, 每个方法里都加个 token 或者 httpservletrequest, 每次需要的时候 都去根据 header/ token (再根据 redis 其他的转换成信息), 但是想想每个 controller service rpc 方法都要带上 token 或者其他的 那也太恐怖了, 不过还有一点.. 如果一个 controller 方法 含有 Httpservletrequest, 那么它的 rpc 方法大概也得带着这么个参数, 那会一直循环循环吗?

    还有就是, 各个服务全关了外网端口, 所有请求都要经过除了网关外的 另一个特定服务, 例如 admin,在这个地方进行鉴权, 查看有没有对应的权限 /数据权限,

    还是经验不足啊...
    yema50
        23
    yema50  
       2020-07-31 09:43:11 +08:00
    @yang957862615 可以的
    jinzhongyuan
        24
    jinzhongyuan  
       2022-01-17 19:28:23 +08:00
    @hantsy 看了一下大纲,是个好仓库
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2883 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 07:55 PVG 15:55 LAX 00:55 JFK 03:55
    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