• api-gateway实践(10)新服务网关


    网关指南: 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

    参考链接:https://help.aliyun.com/document_detail/48019.html?spm=5176.doc29487.6.580.NFBkpz

    参考链接:https://bitbucket.org/b_c/jose4j/wiki/JWT%20Examples

    JSON Web Token (JWT) Code Examples

     

    一、配置中心

    1、配置API时,将所有API分为两类,【获得授权Token的API】和【业务访问API】。

    2、【获得授权Token的API】用于客户端获得token。配置【获得授权Token的API】时,要指定Token对应的KeyId和解析Token的公钥。

    3、【业务访问API】实际业务API,调用时需携带token。配置【业务访问API】时,要指定请求Token名称。

    当客户端调用这类API的请求到达API网关后,API网关自动验证这个请求的Appkey和Token是否合法。

    3.1、系统需要为【业务访问API】增加如下请求query参数:

    3.2、系统自动向后方传递解析后的用户参数(claims)

           参数位置支持:不要往body里放,query、head,默认head。

    二、业务流程

    1、客户端调用 “获取授权 API” ,获取Token的流程

    1.1、客户端使用您的 “Appkey 签名”+“用户名/密码” 调用 “获取授权” API 获取(加密后的)Token

    用户名/密码 是极为敏感的信息,在网络中明文传输存在风险,建议在传输前对用户名密码再次加密,并使用 HTTPS 协议传输。

    1.2、API网关收到请求后,先认证您的 Appkey(签名比对?),认证通过后,调用后端服务的账号系统认证您传递的 “用户名/密码”。

    1.3、后端服务认证通过后,(后端服务)依据网关提供的加密方式,颁发 Token返回给客户端,后续客户端可凭 Token 来调用 “业务 API”。

    2、客户端调用业务类 API ,来实现业务功能

    2.1、客户端(签名比对)使用 “获取授权 API” 得到的 Token 来调用 “业务API”。

    2.2、API 网关认证、解析 Token 的内容(claims),并将 Token 中包含的用户信息(claims)传递给后端。 (ca_x_openid.xxxx -> xxxxx,ca_x_openid.yyyy -> yyyy

           参数位置支持:不要往body里放,query、head,默认head。

    三、认证服务器AS(服务提供者实现)

    认证服务器的职责

    • 认证服务器负责生成 id_Token 并管理公钥私钥对
    • 认证服务器接收网关请求(u+p),执行u+p认证。
      • 认证成功:返回token(包含了用户信息)
      • 认证失败:返回出错信息 注:id_token 必须符合 OIDC(1.0版本)协议中的 规范。

    id_token:id_token 是在 OIDC 协议中定义的一种令牌,详细内容参见 OpenID Connect Core 1.0。

    id_token 的生成需要 KeyPair, keyId 与 Claims (有关Claims更多信息请访问 ID_Token)。

    1、KeyId

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

    参考示例(JAVA)

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

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

    2、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"} 示例代码(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); (3) Claims 通过 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); (4) 通过 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 = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyText)).getPrivateKey(); jws.setKey(privateKey); (5)通过 JWS 获取 id_token 值 示例代码(JAVA) String idToken = jws.getCompactSerialization(); 一个生成的 id_token 示例: eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg4NDgzNzI3NTU2OTI5MzI2NzAzMzA5OTA0MzUxMTg1ODE1NDg5In0.eyJ1c2VySWQiOiIzMzcwMTU0NDA2ODI1OTY4NjI3IiwidGFnTmFtZSI6ImNvbmFuVGVzdCIsImV4cCI6MTQ4MDU5Njg3OSwiYXVkIjoiQWxpX0FQSV9Vc2VyIiwianRpIjoiTm9DMFVVeW5xV0N0RUFEVjNoeEIydyIsImlhdCI6MTQ4MDU5MzI3OSwibmJmIjoxNDgwNTkzMjE5LCJzdWIiOiJ7ZGF0YU1hcD0ne3VzZXJJZD0zMzcwMTU0NDA2ODI1OTY4NjI3fScsIHN0YXR1c0NvZGU9JzAnLCBlcnJvcnM9J1tdJ30ifQ.V3rU2VCziSt6uTgdCktYRsIwkMEMsO_jUHNCCIW_Sp4qQ5ExjtwNt9h9mTGKFRujk2z1E0k36smWf9PbNGTZTWmSYN8rvcQqdsupcC6LU9r8jreA1Rw1CmmeWY4HsfBfeInr1wCFrEfZl6_QOtf3raKSK9AowhzEsnYRKAYuc297gmV8qlQdevAwU75qtg8j8ii3hZpJqTX67EteNCHZfhXn8wJjckl5sHz2xPPyMqj8CGRQ1wrZEHjUmNPw-unrUkt6neM0UrSqcjlrQ25L8PEL2TNs7nGVdl6iS7Nasbj8fsERMKcZbP2RFzOZfKJuaivD306cJIpQwxfS1u2bew

    示例代码(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);

    3、id_token的生成

    3.1、构建 Claims

    通过 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);

    3.2、构建jws

    通过 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);

    3.3、通过 JWS 获取 id_token 值

    示例代码(JAVA)

    String idToken = jws.getCompactSerialization();
    一个生成的 id_token 示例:

    eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg4NDgzNzI3NTU2OTI5MzI2NzAzMzA5OTA0MzUxMTg1ODE1NDg5In0.eyJ1c2VySWQiOiIzMzcwMTU0NDA2ODI1OTY4NjI3IiwidGFnTmFtZSI6ImNvbmFuVGVzdCIsImV4cCI6MTQ4MDU5Njg3OSwiYXVkIjoiQWxpX0FQSV9Vc2VyIiwianRpIjoiTm9DMFVVeW5xV0N0RUFEVjNoeEIydyIsImlhdCI6MTQ4MDU5MzI3OSwibmJmIjoxNDgwNTkzMjE5LCJzdWIiOiJ7ZGF0YU1hcD0ne3VzZXJJZD0zMzcwMTU0NDA2ODI1OTY4NjI3fScsIHN0YXR1c0NvZGU9JzAnLCBlcnJvcnM9J1tdJ30ifQ.V3rU2VCziSt6uTgdCktYRsIwkMEMsO_jUHNCCIW_Sp4qQ5ExjtwNt9h9mTGKFRujk2z1E0k36smWf9PbNGTZTWmSYN8rvcQqdsupcC6LU9r8jreA1Rw1CmmeWY4HsfBfeInr1wCFrEfZl6_QOtf3raKSK9AowhzEsnYRKAYuc297gmV8qlQdevAwU75qtg8j8ii3hZpJqTX67EteNCHZfhXn8wJjckl5sHz2xPPyMqj8CGRQ1wrZEHjUmNPw-unrUkt6neM0UrSqcjlrQ25L8PEL2TNs7nGVdl6iS7Nasbj8fsERMKcZbP2RFzOZfKJuaivD306cJIpQwxfS1u2bew

    四、资源服务器RS

    资源服务器RS

    • 资源服务器RS负责校验 id_token,
    • 并解析出相应的信息 Consumer 用带有 id_token 的参数去请求 API 网关。

    API 网关保存了校验所使用的公钥,验证并解析 id_token 获取其中的 User 信息传给 Provider(ca_x_openid.xxxx->xxxx),若验证失败则直接返回错误信息。

    Provider 处理请求并返回结果给 API 网关。 API 网关透传 Provider 响应的结果给 Consumer。

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

  • 相关阅读:
    JavaScript的for循环编写九九乘法表
    Python核心编程(切片索引的更多内容)
    js/jq宽高的理解与运用
    七月与安生:不管选择哪条路,都会是辛苦的 — —豆瓣老丑
    Linux命令入门
    jq滚动监听-导航滚动
    jQuery页面滚动监听事件及高级效果插件
    跟随鼠标移动展示内容
    用相对定位和负向移动完成图片相框阴影
    腾讯数据总监:运营人员必须掌握的APP基础数据分析体系(没有比这篇更系统全面的)
  • 原文地址:https://www.cnblogs.com/lexiaofei/p/7640343.html
Copyright © 2020-2023  润新知