阿里云API网关(11)API的三种安全认证方式

网关指南: https://help.aliyun.com/document_detail/29487.html?spm=5176.doc48835.6.550.23Oqbl 

网关控制台: https://apigateway.console.aliyun.com/?spm=5176.doc42740.2.2.Q4z5ws#/cn-hangzhou/apis/list

一、安全认证:无认证

在阿里云的文档【API 网关 > 开放 API 接入 API 网关 > 2. 前端配置】说明https://help.aliyun.com/document_detail/48805.html?spm=5176.doc48805.6.546.YPtFTr :

  

二、安全认证:阿里云APP

三、安全认证:OpenConnect

1、获取授权 api

  • 获取授权API:向客户端颁发Token的接口。配置这个API时您需要告知API网关,您Token对应的Key和解析Token使用的公钥。

 

2、业务类接口

  • 业务类接口,是您实际的业务接口,比如获取用户息、进行某个操作等。配置这类API时,你需要告知API网关你请求中表示Token的参数名称。请求到达API网关后,API网关自动认证这个请求是否合法。

四、附录 - OpenID Connect 如何使用

OpenID Connect 是一套基于 OAuth 2.0 协议的轻量级规范,提供通过 API 进行身份交互的框架。较 OAuth 而言, OpenID Connect 方式除了认证请求之外,还标明请求的用户身份。
API 网关依据 OpenConnect 的标准,对用户请求进行 Appkey+Token 校验,Token 由 API 提供者的系统颁发,网关颁发 Appkey,并负责 Appkey、Token 的真伪校验。

实现原理

使用 OpenID Connect认证,将 API 分为 获取授权 API 和 业务 API 两类。
APi

API调用

  • 获取授权API:向客户端颁发Token的接口。配置这个API时您需要告知API网关,您Token对应的Key和解析Token使用的公钥。
  • 业务类接口,是您实际的业务接口,比如获取用户息、进行某个操作等。配置这类API时,你需要告知API网关你请求中表示Token的参数名称。请求到达API网关后,API网关自动认证这个请求是否合法。

认证方式

  1. 客户端调用 获取授权 API

    1. 客户端使用您的 Appkey 签名+用户名/密码 调用 获取授权 API 获取授权。
    2. API 网关收到请求后,先认证您的 Appkey,认证通过后,调用后端服务的账号系统认证您传递的 用户名/密码。

    3. 后端服务认证通过后,返回 Token 给您,您可凭 Token 来调用 业务 API。

  2. 客户端调用业务 API

    1. 客户端使用 获取授权 API 得到的 Token 和 签名后的 Appkey 来调用 业务API。

    2. API 网关认证、解析 Token 的内容,并将 Token 中包含的用户信息传递给后端。

    3. 在此阶段的操作中,API 的提供者需要事先进行如下操作:

      1. 开放账号系统,允许 API 网关对请求中 用户名/密码 进行验证,并依据网关提供的加密方式,颁发 Token。详细内容请参照下文 如何实现 AS 模块。
      2. 在 API 网关定义 API。详细内容参照下文 在 API 网关配置 API。
        注意:用户名/密码 是极为敏感的信息,在网络中明文传输存在风险,建议在传输前对用户名密码再次加密,并使用 HTTPS 协议传输。

实现方案简介

实现方案分为两个重要的部分:

1. Authorization server(AS):认证服务器,负责生成 id_Token 并管理公钥私钥对。

这一步需要您自行实现。实现方法,请参照下文 在 API 网关配置 API。
u_p

参考上图,流程简述如下:

  1. Consumer(调用者)向API网关发送获取 id_token 认证请求,比如:通过用户名和密码(U+P)的方式。
  2. API 网关透传该请求到 AS。
  3. AS 向 Provider(服务提供方)发送认证用户信息请求。
  4. Provider 响应认证结果,若失败则直接响应错误信息。
  5. 认证结果成功,AS 生成 id_token,id_token 中包含了 User 信息(可扩展,也可包含其他必要信息)。
  6. API 网关将 AS 返回的 id_token 响应给 Consumer。

    说明:AS 不用必须是单独部署的应用,完全可以集成在 Provider 中,在整个体系中担任 id_token 生产者角色,所生成的 id_token 必须符合 OIDC(1.0版本)协议中的 规范

2. Resource server(RS):资源服务器,负责校验 id_token,并解析出相应的信息。

此部分由网关来完成。因为 API 网关目前已经集成了 RS 功能,服务提供方只需要按照相应的加密规则生成 id_token 即可。
rs

参考上图,流程简述如下:

  1. Consumer 用带有 id_token 的参数去请求 API 网关。
  2. API 网关会保存校验所使用的公钥,验证并解析 id_token 获取其中的 User 信息传给 Provider,若验证失败则直接返回错误信息。
  3. Provider 处理请求并返回结果给 API 网关。
  4. API 网关透传 Provider 响应的结果给 Consumer。

说明:RS 在整个体系中担任 id_token 消费者角色,只有 id_token 校验通过,才能将请求转发给 Provider。

如何实现 AS 模块

AS 中使用 OIDC 生成 id_token 的说明

  • id_token,也叫 ID Token,是在 OIDC 协议中定义的一种令牌,详细内容参见 OpenID Connect Core 1.0
  • id_token 生成需要 KeyPair, keyId 与 Claims (有关Claims更多信息请访问 ID_Token)。 

KeyId 说明

KeyId 必须保证唯一, 比如使用 UUID 生成的长度至少32位的随机字符串, 可以全为数字或数字+字母。
参考示例(JAVA)

String keyId = UUID.randomUUID().toString().replaceAll("-", "");

String keyId = String.valueOf(UUID.randomUUID().getMostSignificantBits()) + String.valueOf(UUID.randomUUID().getMostSignificantBits());

KeyPair 说明

KeyPair 是一个基于 PKI 体系的非对称算法的公私钥组合, 每一对包括公钥(publicKey)与私钥(privateKey); 公钥放置在 RS 中,在校验(verify)时使用, 私钥放置在 AS 中,在生成 id_token 时做数字签名使用;
KeyPair 使用 RSA SHA256 加密算法, 为保证足够安全其加密的位数为2048;
AS 中使用的 KeyPair 均为 JSON 格式的数据,一个示例如下:
publicKey:

{"kty":"RSA","kid":"67174182967979709913950471789226181721","alg":"ES256","n":"oH5WunqaqIopfOFBz9RfBVVIIcmk0WDJagAcROKFiLJScQ8N\_nrexgbCMlu-dSCUWq7XMnp1ZSqw-XBS2-XEy4W4l2Q7rx3qDWY0cP8pY83hqxTZ6-8GErJm\_0yOzR4WO4plIVVWt96-mxn3ZgK8kmaeotkS0zS0pYMb4EEOxFFnGFqjCThuO2pimF0imxiEWw5WCdREz1v8RW72WdEfLpTLJEOpP1FsFyG3OIDbTYOqowD1YQEf5Nk2TqN\_7pYrGRKsK3BPpw4s9aXHbGrpwsCRwYbKYbmeJst8MQ4AgcorE3NPmp-E6RxA5jLQ4axXrwC0T458LIVhypWhDqejUw","e":"AQAB"}

privateKey:

{"kty":"RSA","kid":"67174182967979709913950471789226181721","alg":"ES256","n":"oH5WunqaqIopfOFBz9RfBVVIIcmk0WDJagAcROKFiLJScQ8N\_nrexgbCMlu-dSCUWq7XMnp1ZSqw-XBS2-XEy4W4l2Q7rx3qDWY0cP8pY83hqxTZ6-8GErJm\_0yOzR4WO4plIVVWt96-mxn3ZgK8kmaeotkS0zS0pYMb4EEOxFFnGFqjCThuO2pimF0imxiEWw5WCdREz1v8RW72WdEfLpTLJEOpP1FsFyG3OIDbTYOqowD1YQEf5Nk2TqN\_7pYrGRKsK3BPpw4s9aXHbGrpwsCRwYbKYbmeJst8MQ4AgcorE3NPmp-E6RxA5jLQ4axXrwC0T458LIVhypWhDqejUw","e":"AQAB","d":"aQsHnLnOK-1xxghw2KP5JTZyJZsiwt-ENFqqJfPUzmlYSCNAV4T39chKpkch2utd7hRtSN6Zo4NTnY8EzGQQb9yvunaiEbWUkPyJ6kM3RdlkkGLvVtp0sRwPCZ2EAYBlsMad9jkyrtmdC0rtf9jerzt3LMLC7XWbnpC3WAl8rsRDR1CGs\_-u4sfZfttsaUbJDD9hD0q4NfLDCVOZoQ\_8wkZxyWDAQGCe6GcCbu6N81fTp2CSVbiBj7DST\_4x2NYUA2KG8vyZYcwviNTxQzk4iPfdN2YQz\_9aMTZmmhVUGlmTvAjE5ebBqcqKAS0NfhOQHg2uR46eBKBy\_OyVOLohsQ","p":"8Tdo3DCs-0t9JMtM0lYqPRP4wYJs37Rv6S-ygRui2MI\_hadTY9I2A199JMYw7Fjke\_wa3gqJLa98pbybdLWkrOxXbKEkwE4uc4-fuNjLbUTC5tqdM5-nXmpL887uREVYnk8FUzvWeXYTCNCb7OLw5l8yPJ1tR8aNcd0fJNDKh98","q":"qlRrGSTsZzBkDgDi1xlCoYvoM76cbmxrCUK-mc\_kBRHfMjlHosxFUnAbxqIBE4eAJEKVfIJLQrHFvIDjQb3kM9ylmwMCu9f8u9DHrT8J7LSDlLqDaXuiM2oiKtW3bAaBPuiR7sVMFcuB5baCebHU487YymJCBTfeCZtFdi6c4w0","dp":"gVCROKonsjiQCG-s6X4j-saAL016jJsw-7QEYE6uiMHqR\_6iJ\_uD1V8Vuec-RxaItyc6SBsh24oeqsNoG7Ndaw7w912UVDwVjwJKQFCJDjU0v4oniItosKcPvM8M0TDUB1qZojuMCWWRYsJjNSWcvAQA7JoBAd-h6I8AqT39tcU","dq":"BckMQjRg2zhnjZo2Gjw\_aSFJZ8iHo7CHCi98LdlD03BB9oC\_kCYEDMLGDr8d7j3h-llQnoQGbmN\_ZeGy1l7Oy3wpG9TEWQEDEpYK0jWb7rBK79hN8l1CqyBlvLK5oi-uYCaiHkwRQ4RACz9huyRxKLOz5VvlBixZnFXrzBHVPlk","qi":"M5NCVjSegf\_KP8kQLAudXUZi\_6X8T-owtsG\_gB9xYVGnCsbHW8gccRocOY1Xa0KMotTWJl1AskCu-TZhOJmrdeGpvkdulwmbIcnjA\_Fgflp4lAj4TCWmtRI6982hnC3XP2e-nf\_z2XsPNiuOactY7W042D\_cajyyX\_tBEJaGOXM"}

生成 KeyPair 参考示例(JAVA)

String keyId = UUID.randomUUID().toString().replaceAll("-", "");

RsaJsonWebKey jwk = RsaJwkGenerator.generateJwk(2048);

jwk.setKeyId(keyId);

jwk.setAlgorithm(AlgorithmIdentifiers.ECDSA\_USING\_P256\_CURVE\_AND\_SHA256);

String publicKey = jwk.toJson(JsonWebKey.OutputControlLevel.PUBLIC\_ONLY);

String privateKey = jwk.toJson(JsonWebKey.OutputControlLevel.INCLUDE\_PRIVATE);

生成 id_token 参考步骤

  1. 通过 OIDC 协议中定义的 Claims 属性(aud, sub, exp, iat, iss)与其属性值,生成 Claims(全称 JwtClaims)

    示例代码(JAVA)

JwtClaims claims = new JwtClaims();

claims.setGeneratedJwtId();

claims.setIssuedAtToNow();

//expire time

NumericDate date = NumericDate.now();

date.addSeconds(120);

claims.setExpirationTime(date);

claims.setNotBeforeMinutesInThePast(1);

claims.setSubject("YOUR_SUBJECT");

claims.setAudience("YOUR_AUDIENCE");

//添加自定义参数

claims.setClaim(key, value);

  1. 通过 keyId, Claims, privateKey 与使用的数字签名算法 (RSA SHA256 )生成 JWS( Json Web Signature)

    示例代码(JAVA)

JsonWebSignature jws = new JsonWebSignature();

jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA\_USING\_SHA256);

jws.setKeyIdHeaderValue(keyId);

ws.setPayload(claims.toJson());

PrivateKey privateKey = newRsaJsonWebKey(JsonUtil.parseJson(privateKeyText)).getPrivateKey();

jws.setKey(privateKey);

  1. 通过 JWS 获取 id_token 值

    示例代码(JAVA)

String idToken = jws.getCompactSerialization();

  1. 一个生成的 id_token 示例:

eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg4NDgzNzI3NTU2OTI5MzI2NzAzMzA5OTA0MzUxMTg1ODE1NDg5In0.eyJ1c2VySWQiOiIzMzcwMTU0NDA2ODI1OTY4NjI3IiwidGFnTmFtZSI6ImNvbmFuVGVzdCIsImV4cCI6MTQ4MDU5Njg3OSwiYXVkIjoiQWxpX0FQSV9Vc2VyIiwianRpIjoiTm9DMFVVeW5xV0N0RUFEVjNoeEIydyIsImlhdCI6MTQ4MDU5MzI3OSwibmJmIjoxNDgwNTkzMjE5LCJzdWIiOiJ7ZGF0YU1hcD0ne3VzZXJJZD0zMzcwMTU0NDA2ODI1OTY4NjI3fScsIHN0YXR1c0NvZGU9JzAnLCBlcnJvcnM9J1tdJ30ifQ.V3rU2VCziSt6uTgdCktYRsIwkMEMsO_jUHNCCIW_Sp4qQ5ExjtwNt9h9mTGKFRujk2z1E0k36smWf9PbNGTZTWmSYN8rvcQqdsupcC6LU9r8jreA1Rw1CmmeWY4HsfBfeInr1wCFrEfZl6_QOtf3raKSK9AowhzEsnYRKAYuc297gmV8qlQdevAwU75qtg8j8ii3hZpJqTX67EteNCHZfhXn8wJjckl5sHz2xPPyMqj8CGRQ1wrZEHjUmNPw-unrUkt6neM0UrSqcjlrQ25L8PEL2TNs7nGVdl6iS7Nasbj8fsERMKcZbP2RFzOZfKJuaivD306cJIpQwxfS1u2bew

在 API 网关配置 API

    1. API 编辑功能中,基本信息栏目中安全认证增加 OpenID Connect 选项,这种方式同时也包括了 阿里云APP 认证方式,也就是说只有被授权的 APP 才能调用这个 API。

      api

    2. 选择 OpenID Connect 这种认证方式后,接下来要选择 OpenID Connect 模式,有两个选项:
      API-2

      1. 获取授权 API:您用来换取 Token 的 API,比如:通过 U+P 换取 Token。
      2. 业务 API:也就是服务提供商提供服务的 API,调用者会把之前获取到的 Token 作为入参进行调用。
        OpenID Connect 认证方式主要包含的就是以上这两种 API,下文将分别说明这两种API 是如何配置的。
    3. 获取授权 API 还需要配置 KeyId 和公钥,见下图:
      pai-3

      KeyId:公钥私钥对 对应的一个唯一 Id,由 As 模块负责生成的;示例:

88483727556929326703309904351185815489

    1. 公钥:负责验证和解析 Token,由 As 模块负责生成的,示例:

{"kty":"RSA","kid":"88483727556929326703309904351185815489","alg":"ES256","n":"ie0IKvKLd7Y3izHcZemdDsVVXg5QtWtGF7XEkILnn66R2\_3a30DikqV409OVL7Hv0ElACgCaBLEgZeGHTcdLE1xxDTna8MMBnBNuMVghvFERCKh8uzpxlQsfcnFd5IFdJWj1x5Tscetrow6lA3h5zYx0rF5TkZzC4DclxgDmITRam0dsHBxr3uk9m9YYBz2mX0ehjY0px7vIo7hZH2J3gODEPorIZkk3x8GPdlaA4P9OFAO4au9-zcVQop9vLirxdwDedk2p-F9GP6UiQC9V2LTWqkVw\_oPBf9Rlh8Qdi19jA8SeCfzAxJZYlbOTK8dYAFAVEFsvXCFvdaxQefwWFw","e":"AQAB"}

    1. 设置完这些,后面的设置就和之前普通的 API 一样了,在此就不赘述了。

      不管是创建 API 还是修改 API,所设置的 KeyId 和公钥都是在 API 发布之后才会生效。

    2. 业务 API 需要配置 Token所对应的参数名称。

      api-4

      1. 如上图,Token 所对应的参数名称:就是调用者调用 API 传入 id_token 所使用的参数名,API 网关会识别这个参数值,校验并解析。

      2. 然后在入参定义中,必须要定义一个对应参数,否则系统会出现错误提示,见下图。api-5

      3. 设置自定义系统参数:业务 API在 定义 API 后端服务 标签中会开放配置自定义系统参数,举个例子,见下图:
        api-6比如:AS 生成的 id_token 中包含了调用者的 userId,那么如果按照上图这样配置的话,就会把从调用者传过来的 id_token 中解析出来的 userId 传给服务提供方,配置方式和系统参数类似。
        除了以上3处,定义 API 其他配置和前文一样,也就不再赘述了。

      以上就是 第三方账号认证 OpenID Connect 在 API 网关配置的全部内容,供您参考!

原文地址:https://www.cnblogs.com/lexiaofei/p/7228265.html