api-gateway实践(10)新服务网关 - OpenID Connect
网关指南: 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
- Producing and consuming a signed JWT
- Using an HTTPS JWKS endpoint
- Using JWKs
- X.509
- Something else? (X.509 Certificates at some HTTPS endpoint, maybe)
- Two-pass JWT consumption
- Producing and consuming a nested (signed and encrypted) JWT
一、配置中心
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。
api-gateway实践(10)新服务网关 - OpenID Connect的更多相关文章
- api-gateway实践(02)新服务网关 - 运行环境
一.服务网关的运行环境 1.服务配置中心 1.1.服务配置中心前台 前台 http://10.110.17.20/#/login:无源码,德奎部署在10.110.17.20的DockerStatck环 ...
- api-gateway实践(03)新服务网关 - 网关请求拦截检查
参考链接:http://www.cnblogs.com/jivi/archive/2013/03/10/2952829.html 一.为什么要拦截检查请求? 防止重放攻击.篡改重放,进行使用规格检查 ...
- api-gateway实践(06)新服务网关 - 请求监控
一.实时监控 用户点击服务实例,系统显示服务实例-version下的api列表, 用户点击某个api的如下两个图标 1.API请求次数监控 横轴:时间,粒度为分钟 纵轴:请求访问次数 展示:失败数(红 ...
- api-gateway实践(04)新服务网关 - 新手入门
一.网关引擎环境 1.下载代码 2.搭建环境 3.打包部署 二.配置中心环境 1.下载代码 2.搭建环境 3.打包部署 三.创建业务实例 1.以租户身份登录配置中心,注册 group.version. ...
- api-gateway实践(13)新服务网关 - 断路保护/熔断机制
参考链接:SpringCloud的Hystrix(五) Hystrix机制 新需求列表 1.在线测试 根据定义,生成输入界面, 点击测试, 验证参数,发起调用,返回执行结果 2.熔断保护 两个实现类: ...
- api-gateway实践(08)新服务网关 - 云端发布和日志查看
一.发布应用 1.新建应用空间 1.1.新建应用空间 1.2.新建应用 1.3.上传程序包 2.创建应用引擎服务 3.发布应用 3.1.为应用容器绑定Web运行环境(应用引擎服务) 3.2.发布应用( ...
- api-gateway实践(07)新服务网关 - 手动发布
应用地址:http://10.110.20.191:8080/api-gateway-engine/ 一.准备工作 1.xshell登陆云主机 1.1.配置链接 1.2.链接成功 1.3.关闭防火墙 ...
- 阿里云API网关(10)服务网关业务流程
一.开放api 二.调用api 三.开发指南 四.其他 1.调试 2.测试 3.mock 4.发布 5.checklist
- [转载] 构建微服务:使用API Gateway
原文: http://mp.weixin.qq.com/s?__biz=MzA5OTAyNzQ2OA==&mid=206889381&idx=1&sn=478ccb35294c ...
随机推荐
- python函数学习(一)
1.parse_known_args()和parse_args()函数 该函数为命令行解析函数,调用时需要import argparse(命令行选项.参数和子命令的解析器). 以下内容摘自python ...
- java单点登录原理与简单实现
一.单系统登录机制 1.http无状态协议 web应用采用browser/server架构,http作为通信协议.http是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关 ...
- 小程序首页onLoad为异步,调用app.js中的全局参数的解决方案。
一,先说一下遇到的问题: 在首页,为了携带app.js中一些参数去做请求动作,但是由于异步原因,发现请求时候,参数信息还未获取到但请求已经发出去. 若等app.js的全局参数返回来,再携带着它去做请求 ...
- Gatling - 用 session 实现关联 传递 token 值
项目中的某个接口必须先登录后调用,但是 header 中的Authorization 需要在登录返回的token中添加一个字串,所以需要先获得 token 并修改后传递给该接口的请求. 虽然这是常见的 ...
- Spring服务定制
问题总述 我们都知道如果使用Spring来进行bean管理的时候.如果同一个接口的实现类存在两个,直接使用@Autowired注解来实现bean注入,会在启动的时候报异常.我们通常的做法是使用@R ...
- shell常见脚本30例
shell常见脚本30例 author:headsen chen 2017-10-19 10:12:12 本文原素材出自网上,特此申明.有些地方加入我自己的改动 常见的30例shell脚本 1.用 ...
- Python上下文管理器
在Python中让自己创建的函数.类.对象支持with语句,就实现了上线文管理协议.我们经常使用with open(file, "a+") as f:这样的语句,无需手动调用f.c ...
- svn 要求commit提交必须加注释(日志) hook
#vim /data/svn/mysvn/hook/pre-commit #!/bin/bashREPOS="$1"TXN="$2" #RES="OK ...
- Vue探索历程(一)
使用vue.js原文介绍:Vue.js是一个构建数据驱动的web界面库.Vue.js的目标是通过尽可能简单的API实现响应式数据绑定和组合的视图组件.vue.js上手非常简单,先看看几个例子: 例一: ...
- React demo:express、react-redux、react-router、react-roter-redux、redux-thunk(一)
近期终于把之前留下的坑填上了(说了好久的要网站重写,总算是写完了),不过最后的在线添加文章,功能虽然做了,后台没把接口加上,实在是没精力去折腾了,公司又有事要忙,现在把从0开始到完成的一个思路来写一下 ...