MyInfo API Data
数据分为两种:政府确认数据和用户个人提供数据。
政府确认数据,是从政府的信息源拿到的,不可以以电子形式更改。个人提供数据是User自己在MyInfo APP 之中提供的,可以以电子形式更改。
FAQ
- MyInfo 不支持IP白名单,但是可以白名单下面的Fully Qualified Domain Names:
- test.api.myinfo.gov.sg
- api.myinfo.gov.sg
- API更新会通过邮件发送,但是并没有提及是哪个邮件……
- MyInfo API 只支持Web-based Integration。 暂时不支持 Native mobile applications
- 关于X.509 的相关问题:
- 在staging 和 production 环境的 key 应该不同
- Key 是由可信的CA 发布的
- 可以在不同的产品之中使用一样的public key,但是要区分staging 和 production 的环境
- 如果架构设计要求获得可信的MyInfo Web SSL certificate, 那么可以从下面的链接拿到:
- 在应用配置(app configurations submission)之中,对于Callback URL 的要求:
- 在staging 和 product 环境用不同的 callback URL
- 使用 static callback URL,动态URL 不支持
- 在staging 和 product 环境之中的callback URL之中使用Fully Qualified Domain Names (FQDN) ,不可以使用静态IP地址或者端口号。
- 有其他问题,support@myinfo.gov.sg
Get started
作为申请的一部分,要将APP 如何和MyInfo 互相调用的步骤用PDF画出来。模版在附件之中。
Technical Requirements
Transcation Log
下面是建议的最小追踪字段:
- NRIC/FIN
- Fields requested from myInfo
- 时间戳
X.509 Public Key
密钥可以从以下被确认的CA获得:
- digiCert
- Entrust
- Comodo
- VeriSign
- GlobalSign
- GeoTrust
TLS 和密码套件
MyInfo 支持 TLS 1.1 和更高版本。
下面是支持的密码套件:
- TLS_RSA_WITH_AES_256_GCM_SHA384
- TLS_RSA_WITH_AES_128_GCM_SHA256
- TLS_RSA_WITH_AES_256_CBC_SHA256
- TLS_RSA_WITH_AES_256_CBC_SHA
- TLS_RSA_WITH_AES_128_CBC_SHA256
- TLS_RSA_WITH_AES_128_CBC_SHA
Callback URLs
除了之前提到过的,为了安全原因应该区分staging 和 production 环境等之外,Callback URLs不应该包含 # 或者 * 符号。
Toturial
Understanding OAuth2.0 flow for MyInfo APIs
全程需要使用三个不同的API。
-
授权 Authorise
API 调用的是 SingPass 的验证流程,然后显示“获取用户同意”的页面,在流程结束之后,系统会返回一个存活期很短的“authorisation code”。
API 是通过浏览器的 302 重定向触发的。
-
令牌 Token
应用服务器唤醒 API 来得到 access token,这个 token 被用来调用 personal API 来获取真实数据。应用要提供和一个有效的“authorisation code” 调用 authorise API 去换取 access token。 整个 token 的存活时间是 30 分钟。
这个API 是server-to-server call,不通过浏览器。
-
个人 Person
这个 API 返回一个 JSON ,包含请求的个人数据。应用需要使用一个有效的 “access token” 来得到 JSON 数据。
这个 API 是一个 server-to-server call。
Tutorial 1:Basic Person API
官方还附带了官方教程,下面是对于官方教程之中某些需要注意的点的理解和标注。
Invoke the Sandbox Person API
在这个部分主要是有一个官方的API 进行不需要授权的访问,作用为给技术人员查看返回类型。
https://sandbox.api.myinfo.gov.sg/com/v3/person-sample/S9812381D
上面这个URL 要使用GET方法。
下面是这个URL 的返回值。
{
"uinfin": {
"lastupdated": "2019-03-26",
"source": "1",
"classification": "C",
"value": "S9812381D"
},
"name": {
"value": "TAN XIAO HUI",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"hanyupinyinname": {
"value": "CHEN XIAO HUI",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"aliasname": {
"value": "TRICIA TAN XIAO HUI",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"hanyupinyinaliasname": {
"value": "TRICIA CHEN XIAO HUI",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"marriedname": {
"value": "",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"sex": {
"code": "F",
"desc": "Female",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"race": {
"code": "CN",
"desc": "CHINESE",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"secondaryrace": {
"code": "EU",
"desc": "EURASIAN",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"dialect": {
"code": "SG",
"desc": "SWISS GERMAN",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"nationality": {
"code": "SG",
"desc": "SINGAPORE CITIZEN",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"dob": {
"value": "1958-05-17",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"birthcountry": {
"code": "SG",
"desc": "SINGAPORE",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"residentialstatus": {
"code": "C",
"desc": "Citizen",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"passportnumber": {
"value": "E35463874W",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"passportexpirydate": {
"value": "2020-01-01",
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
"regadd": {
"type": "SG",
"block": {
"value": "548"
},
"building": {
"value": ""
},
"floor": {
"value": "09"
},
"unit": {
"value": "128"
},
"street": {
"value": "BEDOK NORTH AVENUE 1"
},
"postal": {
"value": "460548"
},
"country": {
"code": "SG",
"desc": "SINGAPORE"
},
"classification": "C",
"source": "1",
"lastupdated": "2019-03-26"
},
...
}
Tutorial 2
在这个教程之中,官方提供了一个本机运行的程序,可以在这个程序之中的LOG看到API调用过程的交互记录。
https://github.com/ndi-trusted-data/myinfo-demo-app
首先要安装Node 和 NPM,我个人推荐使用 Homebrew 安装,方便快捷。
然后在Pull的项目文件夹之中使用 npm install,再打开命令 ./start.sh
。默认程序在http://localhost:3001
之中执行。
Trigger MockPass Login and Consent(authorise API)
其大体过程为:authorise 的结尾点出发 MockPass 的登陆(实际开发之中是 SingPass 的登陆), 并且在成功登陆之后展示授权页面(consent page)。
点击“Retrive MyInfo”按钮,应用会使用下面的 URL:
https://sandbox.api.myinfo.gov.sg/com/v3/authorise
在URL 之中有下面的参数:
PARAMETER | DESCRIPTION |
---|---|
client_id | 每个应用不同的ID,在示例之中是 STG2-MYINFO-SELF-TEST |
attributes | 用逗号分隔,这个是必选项,可用的 attribute 在 Person 的定义之中都有 |
purpose | 要数据的作用。这个 purpose 会展示在用户的界面,告知为何使用此数据 |
state | identifier to reconcile query and response. This will be sent back to you via the callback URL. Use a unique system generated number for each and every call. |
redirect_uri | 给MyInfo 返回 authorisation code 的URL,在此示例程序之中为 http://localhost:3001/callback |
在授权页面点击 “I Agree” 之后,会进入获得Authorisation’ Code的环节,在 console 的 URL dialog 之中可以看到类似于下方的信息:
http://localhost:3001/callback?code=e2369168-52da-421a-b70f-03f64e779c4b&scope=edulevel%20regadd%20mobileno%20hanyupinyinname%20marriedname%20assessableincome%20cpfcontributions%20email%20housingtype%20race%20sex%20hdbtype%20cpfbalances%20hanyupinyinaliasname%20marital%20aliasname%20nationality%20dob%20name&iss=http%3A%2F%2Fstg-auth.app.gov.sg%3A80%2Fconsent%2Foauth2&state=123&client_id=myinfo
这个URL之中以下信息是非常重要的:
code 之后的一串标志符,API之中叫做 authorisation ,这个案例之中是 e2369168-52da-421a-b70f-03f64e779c4b, 这个标识符在后面要用来唤醒另一个API。
在授权页面(有是否同意的那个页面) 点击同意之后, token 和 person 的 API 会自动在后端唤醒,下面是这两个API 的内容。
Call the Token API
如果已经有了authorisation code, 那么就可以使用 token API 来获得 access token了。
注意:
这个API 必须通过服务器端调用,不可以从浏览器端和移动端调用,因为无法存储私钥。
所以下面的信息不在浏览器的调试端口之中出现,而是在后端打开的Terminal 之中出现。
如果想看具体的代码,可以看 routes/index.js
,其功能为生成TOKEN 的 POST 请求。
示例程序调用的是 https://sandbox.api.myinfo.gov.sg/com/v3/token ,注意其方法为POST
POST 的body 之中可选的参数为:
PARAMETER | DESCRIPTION |
---|---|
grant_type | TOKEN的类型 (默认为 “authorization_code”) |
code | authorise API 提供的authcode |
redirect_uri | 提供给 MyInfo 使用的 callback URL, 示例程序之中的是 http://localhost:3001/callback |
client_id | 之前提到过的每个应用不同的ID,示例程序之中为 STG2-MYINFO-SELF-TEST |
client_secret | 授予程序的密钥,在示例程序之中为 44d953c796cccebcec9bdc826852857ab412fbe2 |
在发完请求之后,可以在Terminal 之中的Log 看到Token API 的回应消息。
Response from Token API:{"access_token":"eyJ0eXAiOiJKV1QiLCJ6aXAiOiJOT05FIiwia2lkIjoiRWtnWkZDeG5taXY2T2JDZ3B4blRIRUkyK3FVPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJTOTgxMjM4MUQiLCJjdHMiOiJPQVVUSDJfU1RBVEVMRVNTX0dSQU5UIiwiYXV0aF9sZXZlbCI6MCwiYXVkaXRUcmFja2luZ0lkIjoiYzNjOTU1MjUtNzEwYS00ZjU3LWFhZTMtMzEzMjUwZDkxOWE3LTEzOTc3NiIsImlzcyI6Imh0dHBzOi8vY29uc2VudC5jbG91ZC5teWluZm8uZ292LnNnL2NvbnNlbnQvb2F1dGgyL3JlYWxtcy9yb290L3JlYWxtcy9teWluZm8tY29tIiwidG9rZW5OYW1lIjoiYWNjZXNzX3Rva2VuIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImF1dGhHcmFudElkIjoiZDVzZ3RWZHl1UFNOc0haTHJkYVUyMTAwTV9zIiwiYXVkIjoibXlpbmZvIiwibmJmIjoxNTUzNTk0OTc4LCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwic2NvcGUiOlsiZWR1bGV2ZWwiLCJtb2JpbGVubyIsImFzc2Vzc2FibGVpbmNvbWUiLCJvd25lcnByaXZhdGUiLCJuYXRpb25hbGl0eSIsImRvYiIsImNwZmNvbnRyaWJ1dGlvbnMiLCJlbWFpbCIsInNleCIsImhvdXNpbmd0eXBlIiwiY3BmYmFsYW5jZXMiLCJuYW1lIiwicmVnYWRkIiwicmFjZSIsImhkYnR5cGUiLCJtYXJpdGFsIiwiYXNzZXNzeWVhciJdLCJhdXRoX3RpbWUiOjE1NTM1OTQ3NzIsInJlYWxtIjoiL215aW5mby1jb20iLCJleHAiOjE1NTM1OTY3NzgsImlhdCI6MTU1MzU5NDk3OCwiZXhwaXJlc19pbiI6MTgwMCwianRpIjoieGRIN1QwSjI0TmFHS1FpWWVnNjcyREJfZGdrIn0.jbdjui3WLe-cwPRDCCR09ya5fK4UUntx31Y87PosGV_FTnKTmiy_cYOeaVTpjLmPx4ebo0fLooPHpKH_5_4lFPVaNdQkOGjvScV1fl04DR1UW0uutQubkIalYW-WgmIDhQz4ZddXyLswUnGc7-eURR47VDzjiMr-ptcn0uSfrI1RNgnc8kY12slOAE4bGxxmYE_PlBLQuZiCdORD9JKKjEKAptKVyQF7p9o6EAg2TQe4cpwcDLXYUkwjLcaoEdCXmX16QICFm9RsVFaW_PRl29fY9ErxcN27UrRnj4mqfbYUuRnN-W2e6DSnMfkZwMRKOlmPgD7fflfh5dnuNwGAXQ","scope":"edulevel mobileno assessableincome ownerprivate nationality dob cpfcontributions email sex housingtype cpfbalances name regadd race hdbtype marital assessyear","token_type":"Bearer","expires_in":1799}
可以看到其主要分为三个方面:access token, token type 和 expire time。
JWT的组成
JWT由三部分组成,Header,Payload,Signature。所以一个典型的 JWT 是 xxxxx.yyyyy.zzzzz
Header 部分和 Payload 部分是 Base64Url 编码的,signature 是一个加密和和一个 Hashing 算法一起使用产生的。
Call the Person API(With the access token)
有了token 就可以访问Person API 来得到用户信息了,API 的注意事项和之前一样,不可以被浏览器或者native app 调用,只可以被服务器端使用。
API的注意事项和之前一样,也是要有有效的 TOKEN, 不然直接拒绝。
这一步的操作逻辑在 index.js
之中,其逻辑主要是为了发送请求做准备,所以要对请求头和请求内容做生成。在请求之中的参数有:
PARAMETER | DESCRIPTION |
---|---|
client_id | 应用程序的独特的ID,示例程序为 STG2-MYINFO-SELF-TEST |
attributes | comma separated list of attributes requested. Possible attributes are listed in the Person object definition in the API specifications. |
在请求头之中提供Access Token
Access Token 应该在API 的header之中提供。
在Terminal之中可以看到类似于下面的内容:
headers:{"Cache-Control":"no-cache","Authorization":"Bearer eyJ0eXAiOiJKV1QiLCJ6aXAiOiJOT05FIiwia2lkIjoiRWtnWkZDeG5taXY2T2JDZ3B4blRIRUkyK3FVPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJTOTgxMjM4MUQiLCJjdHMiOiJPQVVUSDJfU1RBVEVMRVNTX0dSQU5UIiwiYXV0aF9sZXZlbCI6MCwiYXVkaXRUcmFja2luZ0lkIjoiYzNjOTU1MjUtNzEwYS00ZjU3LWFhZTMtMzEzMjUwZDkxOWE3LTEzOTc3NiIsImlzcyI6Imh0dHBzOi8vY29uc2VudC5jbG91ZC5teWluZm8uZ292LnNnL2NvbnNlbnQvb2F1dGgyL3JlYWxtcy9yb290L3JlYWxtcy9teWluZm8tY29tIiwidG9rZW5OYW1lIjoiYWNjZXNzX3Rva2VuIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImF1dGhHcmFudElkIjoiZDVzZ3RWZHl1UFNOc0haTHJkYVUyMTAwTV9zIiwiYXVkIjoibXlpbmZvIiwibmJmIjoxNTUzNTk0OTc4LCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwic2NvcGUiOlsiZWR1bGV2ZWwiLCJtb2JpbGVubyIsImFzc2Vzc2FibGVpbmNvbWUiLCJvd25lcnByaXZhdGUiLCJuYXRpb25hbGl0eSIsImRvYiIsImNwZmNvbnRyaWJ1dGlvbnMiLCJlbWFpbCIsInNleCIsImhvdXNpbmd0eXBlIiwiY3BmYmFsYW5jZXMiLCJuYW1lIiwicmVnYWRkIiwicmFjZSIsImhkYnR5cGUiLCJtYXJpdGFsIiwiYXNzZXNzeWVhciJdLCJhdXRoX3RpbWUiOjE1NTM1OTQ3NzIsInJlYWxtIjoiL215aW5mby1jb20iLCJleHAiOjE1NTM1OTY3NzgsImlhdCI6MTU1MzU5NDk3OCwiZXhwaXJlc19pbiI6MTgwMCwianRpIjoieGRIN1QwSjI0TmFHS1FpWWVnNjcyREJfZGdrIn0.jbdjui3WLe-cwPRDCCR09ya5fK4UUntx31Y87PosGV_FTnKTmiy_cYOeaVTpjLmPx4ebo0fLooPHpKH_5_4lFPVaNdQkOGjvScV1fl04DR1UW0uutQubkIalYW-WgmIDhQz4ZddXyLswUnGc7-eURR47VDzjiMr-ptcn0uSfrI1RNgnc8kY12slOAE4bGxxmYE_PlBLQuZiCdORD9JKKjEKAptKVyQF7p9o6EAg2TQe4cpwcDLXYUkwjLcaoEdCXmX16QICFm9RsVFaW_PRl29fY9ErxcN27UrRnj4mqfbYUuRnN-W2e6DSnMfkZwMRKOlmPgD7fflfh5dnuNwGAXQ"}
做完之后,可以在Terminal 之中看到所请求的客户信息内容:
Person Data (Decoded):
{"name":{"lastupdated":"2019-03-26","source":"1","classification":"C","value":"TAN XIAO HUI"},"sex":{"lastupdated":"2019-03-26","code":"F","source":"1","classification":"C","desc":"FEMALE"},"race":{"lastupdated":"2019-03-26","code":"CN","source":"1","classification":"C","desc":"CHINESE"},"nationality":{"lastupdated":"2019-03-26","code":"SG","source":"1","classification":"C","desc":"SINGAPORE CITIZEN"},"dob":{"lastupdated":"2019-03-26","source":"1","classification":"C","value":"1998-06-06"},"email":{"lastupdated":"2019-03-26","source":"2","classification":"C","value":"myinfotesting@gmail.com"},"mobileno":{"lastupdated":"2019-03-26","source":"2","classification":"C","areacode":{"value":"65"},"prefix":{"value":"+"},"nbr":{"value":"97399245"}},"regadd":{"country":{"code":"SG","desc":"SINGAPORE"},"unit":{"value":"128"},"street":{"value":"BEDOK NORTH AVENUE 4"},"lastupdated":"2019-03-26","block":{"value":"102"},"source":"1","postal":{"value":"460102"},"classification":"C","floor":{"value":"09"},"type":"SG","building":{"value":"PEARL GARDEN"}},"housingtype":{"lastupdated":"2019-03-26","code":"","source":"1","classification":"C","desc":""},"hdbtype":{"lastupdated":"2019-03-26","code":"113","source":"1","classification":"C","desc":"3-ROOM FLAT (HDB)"},"marital":{"lastupdated":"2019-03-26","code":"2","source":"1","classification":"C","desc":"MARRIED"},"edulevel":{"lastupdated":"2019-03-26","code":"3","source":"2","classification":"C","desc":"SECONDARY"},"ownerprivate":{"lastupdated":"2019-03-26","source":"1","classification":"C","value":false},"cpfcontributions":{"lastupdated":"2019-03-26","source":"1","history":[{"date":{"value":"2018-02-18"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2018-01"}},{"date":{"value":"2018-03-18"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2018-02"}},{"date":{"value":"2018-04-18"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2018-03"}},{"date":{"value":"2018-05-18"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2018-04"}},{"date":{"value":"2018-05-27"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2018-05"}},{"date":{"value":"2018-07-15"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-01"}},{"date":{"value":"2017-02-01"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-01"}},{"date":{"value":"2017-02-12"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-02"}},{"date":{"value":"2017-02-21"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-02"}},{"date":{"value":"2017-03-01"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-02"}},{"date":{"value":"2017-03-12"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-03"}},{"date":{"value":"2017-03-21"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-03"}},{"date":{"value":"2017-04-01"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-03"}},{"date":{"value":"2017-04-12"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-04"}},{"date":{"value":"2017-04-21"},"employer":{"value":"Crystal Horse Invest Pte Ltd"},"amount":{"value":500},"month":{"value":"2017-04"}}],"classification":"C"},"cpfbalances":{"oa":{"value":1581.48},"ma":{"value":11470.7},"lastupdated":"2019-03-26","source":"1","classification":"C","sa":{"value":21967.09},"ra":{"value":0}},"uinfin": {"lastupdated": "2019-03-26","source": "1","classification": "C","value": "S9812381D"
}}
Tutorial 3:Implementing PKI Digital Signature
首先要生成Public/Private Key Pair,这一步不多说。
给请求添加签名
签名请求需要的步骤如下:
- 创建一个 Authorisation Token
- 生成 Signature Base String
- 使用数字签名来得到签名之后的 Base String
- 组装 Header
下面是每一步之中需要注意的点:
-
创建一个 Authorisation Token
NAME DESCRIPTION app_id 应用的独特ID,示例STG2-MYINFO-SELF-TEST` nonce 一个随机的String,对于每个请求都是独立生成的。用来分辨请求。 signature_method 签名方式. Value = RS256 signature 签名值 timestamp 从1970年1月1日 GMT 的毫秒数 -
生成Signature Base String
Base String 是用来代表请求内容的String,可以被用来确认内容在传输的过程之中没有被修改。
下面是在Person API 之中的 Base String 的内容:
baseString: GET&https://test.api.myinfo.gov.sg/com/v3/person/S9812381D/&app_id=STG2-MYINFO-SELF-TEST&attributes=name,sex,race,nationality,dob,email,mobileno,regadd,housingtype,hdbtype,marital,edulevel,assessableincome,hanyupinyinname,aliasname,hanyupinyinaliasname,marriedname,cpfcontributions,cpfbalances&client_id=STG2-MYINFO-SELF-TEST&nonce=150589435395700&signature_method=RS256×tamp=1505894353957
Signature Base String 的生成方式如下:
首先按照字典排序来将parameter 进行排序,如果几个parameter 分享一个key, 那么再对其使用 value 进行排序,例子如下:
-
a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t
所有的parameter之间使用&来进行链接,例子如下:
-
a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t
-
建立请求URL
Signature Base String 包括请求的 绝对URL,在 Signature base String 之中使用的URL 必须:
- 包括 Scheme,authority 和 path
- 不包含 query 和 fragment
URL scheme 和 authority 必须是小写字母, 并且必须包括除了80和443之外的接口。
HTTP 请求必须用 & 连接在一起,哪怕是空的请求也一定要这样。
对Base String 做签名来获得数字签名
当Signature Base String 创建之后,下一步就是签名
- 用SHA-2 算法来产生Signature Base String 的 hash
- 用应用的私钥来签名hashed value
- 用 Base64-encode 来对signature value 签名
注意: Base64 编码不应该包含 CRLF,整个 Base64 编码都不应该有换行。
- 将这个字符串作为Signature参数的值
下面是示例的Java 代码:
String baseString = "Constructed base string";
Signature sig = Signature.getInstance("RSA-SHA256");
sig.initSign(privateKey); // Get private key from keystore
sig.update(baseString.getBytes());
byte[] signedData = sig.sign();
String finalStr = Base64.getEncoder().encodeToString(signedData);
Assembling the header 组装头部
已经有了数字签名之后,就可以将最终的header 装配好。下面的部分是在header 之中需要包括的:
- App_id
- nonce
- Signature_method
- signature
- timestamp
这些参数在之前都有讲过,就不再赘述了。
下面是带有authorization parameter 的示例头部:
Authorization: PKI_SIGN
timestamp="1505900210349",
nonce="150590021034800",
app_id="STG2-MYINFO-SELF-TEST",
signature_method="RS256",
signature="EEm+HEcNQajb5FkVd82zjojk+daYZXxSGPCOR2GHZeoyjZY1PK+aFMzHfWu7eJZYMa5WaEwWxdOdq5hjNbl8kHD7bMaOks7FgEPdjE++TNomfv7SMktDnIvZmPYAxhjb/C9POU2KT6tSlZT/Si/qMgD1cryaPwSeMoM59UZa1GzYmqlkveba7rma58uGwb3wZFH0n57UnouR6LYXDOOLkqi8uMZBuvRUvSJRXETAj2N0hT+4QJiN96Ct6IEQh/woZh0o74K5Ol9PpDSM08qC7Lj6N/k694J+hbBQVVviGn7/6mDkfbwdMDuoKs4t7NpqmAnwT+xaQSIZcexfrAVQYA=="
在确认好之后,将请求发送出去,要确认URL 的域,例如 https://api.myinfo.gov.sg/com/v3/*
在接受请求的回应之后,要核实请求的 JWT 是否是有效的。