OpenID Connect 是一套基于 OAuth 2.0 协议的轻量级规范,提供经过 API 进行身份交互的框架。html
OpenID Connect 使用简单的REST / JSON消息,开发者能够轻松集成。算法
OpenID Connect 容许全部类型的客户,包括基于浏览器的JavaScript和本机移动应用程序。浏览器
OpenID Connect 容许应用程序和网站的开发人员验证跨网站和应用程序的用户,却无需承担责任存储和管理用户密码。安全
OpenID Connect 规范是开放的, 旨在鼓励一个开放的身份提供商生态系统。 服务器
较 OAuth 而言, OpenID Connect 方式除了认证请求以外,还识别请求的用户身份。 数据结构
OpenID Connect是OpenID的第三代技术。 框架
OpenID Connect,外包所需的Web的内置TLS加密(也称为HTTPS和SSL)的基础设施,这些基础设备广泛地在客户端和服务器平台上实现。 dom
OpenID Connect签名时使用标准JSON WEB TOKEN(JWT)数据结构。这让开发人员极大地更加容易实现OpenID Connect,在实践中有更好的互操做性。网站
在 Api服务网关场景中,Api网关(使用OpenID Connect)对 DevApp 发送的用户请求进行 Appkey+Token 校验ui
Api服务网关,使用 OpenID Connect认证,将 服务提供者的API 分为 获取受权 API 和 业务 API 两类。
阿里云的API 网关目前已经集成了 RS 功能,服务提供方只须要按照相应的加密规则生成 id_token 便可。
id_token( ID Token),是在 OIDC 协议中定义的一种令牌,id_token 生成须要 KeyPair, keyId 与 Claims
id_token: 详细内容参见 OpenID Connect Core 1.0
claims: 更多信息请访问 ID_Token
KeyId 必须保证惟一, 好比使用 UUID 生成的长度至少32位的随机字符串, 能够全为数字或数字+字母。
参考示例(JAVA)
String keyId = UUID.randomUUID().toString().replaceAll("-", "");
或
String keyId = String.valueOf(UUID.randomUUID().getMostSignificantBits()) + String.valueOf(UUID.randomUUID().getMostSignificantBits());
KeyPair 是一个基于 PKI 体系的非对称算法的公私钥组合, 每一对包括公钥(publicKey)与私钥(privateKey);
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);
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);
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);
String idToken = jws.getCompactSerialization();
一个生成的 id_token 示例:
eyJhbGciOiJSUzI1NiIsImtpZCI6Ijg4NDgzNzI3NTU2OTI5MzI2NzAzMzA5OTA0MzUxMTg1ODE1NDg5In0.eyJ1c2VySWQiOiIzMzcwMTU0NDA2ODI1OTY4NjI3IiwidGFnTmFtZSI6ImNvbmFuVGVzdCIsImV4cCI6MTQ4MDU5Njg3OSwiYXVkIjoiQWxpX0FQSV9Vc2VyIiwianRpIjoiTm9DMFVVeW5xV0N0RUFEVjNoeEIydyIsImlhdCI6MTQ4MDU5MzI3OSwibmJmIjoxNDgwNTkzMjE5LCJzdWIiOiJ7ZGF0YU1hcD0ne3VzZXJJZD0zMzcwMTU0NDA2ODI1OTY4NjI3fScsIHN0YXR1c0NvZGU9JzAnLCBlcnJvcnM9J1tdJ30ifQ.V3rU2VCziSt6uTgdCktYRsIwkMEMsO_jUHNCCIW_Sp4qQ5ExjtwNt9h9mTGKFRujk2z1E0k36smWf9PbNGTZTWmSYN8rvcQqdsupcC6LU9r8jreA1Rw1CmmeWY4HsfBfeInr1wCFrEfZl6_QOtf3raKSK9AowhzEsnYRKAYuc297gmV8qlQdevAwU75qtg8j8ii3hZpJqTX67EteNCHZfhXn8wJjckl5sHz2xPPyMqj8CGRQ1wrZEHjUmNPw-unrUkt6neM0UrSqcjlrQ25L8PEL2TNs7nGVdl6iS7Nasbj8fsERMKcZbP2RFzOZfKJuaivD306cJIpQwxfS1u2bew