例如简单判断有没有权限调用某个接口,我在 gateway 里的 filter 判断一下这个 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 网关的鉴权和数据权限该怎么做?
1
gaius 2020-03-11 15:40:47 +08:00 via Android
网关调鉴权服务完事把用户信息和权限列表写到 header
|
2
359889741 2020-03-11 15:41:23 +08:00
filter 里面读出 userId 来,再往业务服务传递不就行了
|
3
wuzhizuiguo OP @gaius 谢谢. 这样在 user-service 里, 对应的方法怎么获取 header 里的写入的信息, 感觉需要在接收的 controller 方法里,添加上 HttpServletRequest 参数, 这样的话 admin 等其他服务也 rpc 调用这个接口 会不会有影响.
|
4
wuzhizuiguo OP @359889741 谢谢, 这样感觉可行, 是收经过网关 需要鉴权的的都要 把 token 里的 userId 取出来了. 是指修改请求的参数, 把 userId 放入到 post 的请求 body 里 或者 get 的 param 中吗
|
5
hantsy 2020-03-11 16:15:49 +08:00
也就是说其它里面的 Service 不做安全验证,这样跟裸奔有什么差别。
|
6
hantsy 2020-03-11 16:17:58 +08:00
既然用到 Redis,直接上 Spring Session ( Redis )就好了,Session 里面想丢什么就什么了,一个用户对象也可以。
|
7
hantsy 2020-03-11 16:19:31 +08:00
用 Spring Session+Spring Security 控制安全就可以了,https://github.com/hantsy/spring-microservice-sample
|
8
wuzhizuiguo OP @hantsy 这个我看网上是这样的, 其他的 service 不对外开放(放到内网 或者防火墙关了访问端口), 即经过网关校验后 各个服务之间是可以信任的.
|
9
hantsy 2020-03-11 16:26:01 +08:00
不知道这种思维方式哪里来的。。。
你网关是会对外吧,如果别人能够进入你网关呢?不一样可以再进入里面的服务。 |
10
wuzhizuiguo OP @hantsy 是的.. 网关是对外的,如果网关通过了, 那按照我这种,确实是可以按照它的接口权限 访问对应的接口 /服务. 有博客也提到了 spring security . 谢谢, 我也去了解学习下
|
11
yang957862615 2020-03-11 17:09:45 +08:00 1
实现 GlobalFilter 接口之后使用 ServerWebExchange.getRequest().mutate().header(String headerName, String... headerValues)这个方法就行
|
12
wuzhizuiguo OP @yang957862615 谢谢. 那再下个服务里怎么获取到这个 header 里的值呢? 感觉方法里还是需要添加 HttpServletRequest 参数...
|
13
yang957862615 2020-03-11 17:15:45 +08:00
@wuzhizuiguo springboot 可以在类里面注入 HttpServletRequest 实例就可以不用在方法上加这个参数
|
14
humpy 2020-03-11 17:19:59 +08:00
|
15
caotian 2020-03-11 17:21:06 +08:00
如果 JWT 可以满足要求, 不需要用 redis 来存 token, gateway 可以只验证 jwt 是否有效, 然后取出 jwt 里的 userId, 转发请求的时候, 再把 userId 放到 header 里
|
16
wuzhizuiguo OP @yang957862615 谢谢
|
17
wuzhizuiguo OP @humpy 还可以这样.. 第一次看到 谢谢.
|
18
wuzhizuiguo OP @caotian 谢谢. 是的, jwt token 也可以.
|
19
rykinia 2020-03-12 09:22:29 +08:00
@hantsy gateway 设置规则,让对外的接口为 /api/**。比如实际的接口是 /user,那么外网调用的 URI 则应该是 /api/user,然后 gateway 转发,这样外网应该没法直接通过 /user 访问吧
|
20
wuzhizuiguo OP @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 |
21
wuzhizuiguo OP @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); |
22
wuzhizuiguo OP 头晕. 暂时放弃了.
选用 将 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,在这个地方进行鉴权, 查看有没有对应的权限 /数据权限, 还是经验不足啊... |
23
yema50 2020-07-31 09:43:11 +08:00
@yang957862615 可以的
|
24
jinzhongyuan 2022-01-17 19:28:23 +08:00
@hantsy 看了一下大纲,是个好仓库
|