云原生API网关支持自定义鉴权服务,方便在网关入口处完成鉴权,避免每个后端服务都接入鉴权服务。本文介绍如何为云原生API网关配置自建认证鉴权。
背景信息
服务端通常根据客户端请求携带的凭证信息(即Token)来保护对外暴露的API接口的通信安全。Token形式没有严格规定,一般根据实际业务场景决定。
如果Token采用的是JSON WEB Token (JWT),那么在任何时间、任何地点都可以利用公钥来对Token的签名进行验签,无需访问一个中心化的鉴权服务。
如果Token的形式是业务方自定义的格式,则服务端收到请求后,必须额外访问中心化的鉴权服务来完成鉴权操作,以此保护API接口的通信安全。云原生API网关支持自定义鉴权。
下面以一个示例来说明云原生API网关接入自建的鉴权服务后的请求处理流程。
客户端向网关发起认证请求,例如登录操作。
网关将认证请求直接转发给认证服务。
认证服务读取请求中的验证信息(例如用户名、密码)进行验证,验证通过后返回凭证信息(Token)给网关,由网关响应给客户端。
客户端向网关发起业务请求,例如下单操作/order,请求中携带上一步中身份认证成功后颁发的Token。
网关通过截取原始业务请求的Path(包含Query Parameters)、HTTP方法(GET、POST等)和Token来形成一个新的请求报文,向接入的自建鉴权服务发起鉴权请求。您需要在网关控制台配置Token所在的HTTP Header,另外您可以根据需要开启允许携带原始请求的Body。
假设自建鉴权服务的鉴权API是/validateToken,那么鉴权请求的真实Path是鉴权API加上原始业务请求的Path后的结果,即/validateToken/order。
鉴权服务收到鉴权请求后,既可以根据Token完成校验Token合法性的操作,又可以根据原始业务请求的Path完成鉴权操作。
如果您鉴权服务的鉴权响应可以修改HTTP状态码,那么您可以利用HTTP状态码来反映鉴权结果。
鉴权服务返回HTTP状态码为200,表明Token合法且Token有权限访问该后端资源。网关继续将原始业务请求转发给受保护的后端服务,收到业务响应后再次转发给客户端,完成下单操作。
鉴权服务返回HTTP状态码为401或者403,表明Token不合法或Token无权限访问该后端资源。网关直接返回鉴权服务的响应给客户端,此次下单操作失败。
如果您的鉴权服务受业务本身限制要求鉴权响应的HTTP状态码统一为200,那么您可以利用内置的HTTP头部
x-mse-external-authz-check-result
。鉴权服务的响应头部
x-mse-external-authz-check-result
的结果为true
,表明Token合法或Token有权限访问该后端资源。网关继续将原始业务请求转发给受保护的后端服务,收到业务响应后再次转发给客户端,完成下单操作。鉴权服务的响应头部
x-mse-external-authz-check-result
的结果为false
,表明Token不合法或Token无权限访问该后端资源。网关直接返回鉴权服务的响应给客户端,此次下单操作失败。
创建自建认证鉴权
登录云原生API网关控制台。
在左侧导航栏,选择实例,并在顶部菜单栏选择地域。
在实例页面,单击目标网关实例名称。
在左侧导航栏,单击
。在全局认证鉴权页面,单击创建鉴权,然后在创建鉴权面板,配置网关鉴权相关参数,最后单击确定。
配置项
说明
开启
是否开启云原生API网关鉴权。
鉴权名称
自定义云原生API网关鉴权的名称。
鉴权类型
选择自建的鉴权服务。
鉴权服务
选择鉴权的后端服务,可以在服务管理中添加。相关内容,请参见添加服务。
说明仅支持选择HTTP协议的服务,不支持Dubbo等其他协议的服务。
如果具有多个端口的K8s Service,则默认取第一个端口。如果您希望使用其他端口,需要在容器服务中创建一个额外的K8s Service且只使用目标端口。
鉴权API
设置鉴权服务提供的鉴权API的Path,API的Path需是前缀匹配。
例如,您的鉴权服务基于SpringMVC构建,对外开放的鉴权API为/check,那么处理/check/**的请求设置如下:
@RequestMapping("/check/**") public ResponseEntity<RestResult<String>> check(){}
Token位置
设置Token在请求报文中的Header位置,常见的有Authorization和Cookie。您可以选择下拉选择或手动输入的方式设置Token位置。
鉴权请求中允许携带的头部
如果需要额外携带客户端请求中的头部,那么需要在字段中按需配置头部。
说明Host、Method、Path和Content-Length头部会被默认添加,您无需手动添加。
鉴权响应中允许保留的头部
如果需要将鉴权响应中的头部添加到客户端请求中,那么需要在字段中按需配置头部。
说明如果客户端请求中已经有该头部,那么其值将会被覆盖。
鉴权请求中允许携带Body
勾选鉴权请求中允许携带Body后,鉴权请求会包含原始请求的Body。
其中,Body最大字节数表示允许鉴权请求携带Body的最大字节数。单位:字节。
超时时间
设置等待鉴权服务返回结果的最大等待时间。单位:秒,默认超时时间为10秒。
模式
支持宽松模式和严格模式,建议您使用宽松模式。
宽松模式:当鉴权服务不可用时(鉴权服务建立连接失败或者返回5xx请求),网关接受客户端请求。
严格模式:当鉴权服务不可用时(鉴权服务建立连接失败或者返回5xx请求),网关拒绝客户端请求。
简单条件授权
在授权右侧单击简单条件。简单条件授权模式支持白名单模式和黑名单模式。
白名单模式:白名单中的Hosts和Paths无需校验即可访问,其余Hosts和Paths都需要校验。
黑名单模式:黑名单中的Hosts和Paths需要校验,其余Hosts和Paths可直接访问。
单击+ 规则条件,设置请求域名、路径和请求头。
域名:请求访问的域名,即Hosts。
路径(Path):请求访问的接口Path,即Paths。
路径匹配条件:Path支持精确匹配、前缀匹配和正则匹配。
精确匹配:输入完整的Path,例如/app/v1/order。
前缀匹配:输入Path的前缀,并且末尾填一个*。例如,匹配所有以/app开头的请求,那么需设置为/app/*。
正则匹配:正则匹配的语法遵循Google Re2规范。详细信息,请参见Re2语法。
大小写敏感:若选中此项,路径匹配值会区分大小写。
请求头(Header):请求访问的头部信息,即Header。单击+请求头配置,可以配置多个Header,各个Header之间是与的关系。
HeaderKey:Header字段名。
条件:Header支持的匹配条件。
等于:请求Header集合中指定Key的值与输入值相等。
不等于:请求Header集合中指定Key的值与输入值不相等。
存在:请求Header集合中存在输入Key值。
不存在:请求Header集合中不存在输入Key值。
包含:请求Header集合中指定Key的值包含输入值。
不包含:请求Header集合中指定Key的值不包含输入值。
前缀:请求Header集合中指定Key的值以输入值为前缀。
后缀:请求Header集合中指定Key的值以输入值为后缀。
正则:请求Header集合中指定Key的值匹配输入的正则表达式,正则匹配的语法遵循Google Re2规范。详细信息,请参见Re2语法。
值:Header字段的取值。
复杂条件授权
在授权右侧单击复杂条件。
复杂条件授权支持通过YAML配置Envoy的permission数据结构来配置基于与/或/非组合条件逻辑的授权规则。当满足配置的条件时执行鉴权逻辑;不满足条件的请求无需鉴权即可访问。
返回全局认证鉴权页面查看鉴权信息,如果已包含新建的网关鉴权信息,说明网关自建认证鉴权新建成功。
查看并管理鉴权服务
登录云原生API网关控制台。
在左侧导航栏,选择实例,并在顶部菜单栏选择地域。
在实例页面,单击目标网关实例名称。
在左侧导航栏,单击
。在认证鉴权页面,单击目标鉴权规则操作列的详情,可查看当前服务的基本信息和认证配置,也可查看并管理授权信息。
您可在授权信息区域,单击创建授权信息。在对话框中输入请求域名和请求Path,并选择匹配方式,然后单击确定新增授权规则。
相关操作
您还可以执行以下其他操作,管理网关的认证鉴权:
开启鉴权:在全局认证鉴权页面,单击目标鉴权规则操作列的开启,使认证鉴权信息生效。
关闭鉴权:在全局认证鉴权页面,单击目标鉴权规则操作列的关闭,关闭网关认证鉴权信息。
编辑鉴权:在全局认证鉴权页面,单击目标鉴权规则操作列的编辑,可编辑网关认证鉴权信息。
删除鉴权:在全局认证鉴权页面,单击目标鉴权规则操作列的删除,可删除网关认证鉴权信息。
只有在认证鉴权信息关闭的状态下才可执行删除操作。
复杂条件授权示例
正则匹配域名示例
本示例中,只对exampleA.com和exampleB.com两个域名下前缀匹配路径的请求执行鉴权逻辑。注意此处regex字段配置的正则需要完全匹配,而非部分匹配。
本示例中,test.exampleA.com将无法命中条件,无需鉴权即可访问。
permissions:
# and_rules 表示下面的所有 rules 条件同时成立时执行鉴权
- and_rules:
rules:
- url_path:
# 前缀匹配路径
path:
prefix: /
- header:
# 正则匹配
safe_regex_match:
regex: "(exampleA\\.com|exampleB\\.com)"
# 支持HTTP Pseudo-Header规范,可通过":authority"这个Header来获取域名
name: ":authority"
与/或/非多条件组合示例
本示例满足以下条件:
exampleA.com/api前缀开头的请求需要鉴权,但是:
exampleA.com/api/appa/bbb不需要鉴权。
exampleA.com/api/appb/ccc不需要鉴权。
exampleB.com下所有请求需要鉴权,但是:
exampleB.com/api/appa/bbb不需要鉴权。
exampleB.com/api/appb/ccc不需要鉴权。
exampleB.com/api/appc前缀开头的不需要鉴权,但是:
exampleB.com/api/appc/bbb/ccc需要鉴权。
exampleB.com/api/appc/ccc/ddd需要鉴权。
整理逻辑如下图所示:
对应的YAML配置如下:
permissions:
# or_rules 表示下面的所有 rules 条件中,有任意一个条件成立时执行鉴权
- or_rules:
rules:
# and_rules,表示下面所有 rules 同时满足,此 rule 条件才成立
# 规则一
- and_rules:
rules:
- url_path:
path:
exact: /api/appc/bbb/ccc
- header:
exact_match: "exampleB.com"
name: ":authority"
# 规则二
- and_rules:
rules:
- url_path:
path:
exact: /api/appc/ccc/ddd
- header:
exact_match: "exampleB.com"
name: ":authority"
- and_rules:
rules:
# 规则三
- url_path:
path:
prefix: /api/
# not_rule 表示下面的配置不满足时,此 rule 条件才成立
# 规则四
- not_rule:
url_path:
path:
exact: /api/appa/bbb
# 规则五
- not_rule:
url_path:
path:
exact: /api/appb/ccc
- header:
exact_match: "exampleA.com"
name: ":authority"
- and_rules:
rules:
# 规则六
- url_path:
path:
prefix: /
# not_rule 表示下面的配置不满足时,此 rule 条件才成立
# 规则七
- not_rule:
url_path:
path:
exact: /api/appa/bbb
# 规则八
- not_rule:
url_path:
path:
exact: /api/appb/ccc
# 规则九
- not_rule:
url_path:
path:
prefix: /api/appc/
- header:
exact_match: "exampleB.com"
name: ":authority"