myinfo提供三个环境:SANDBOX(https://sandbox.api.myinfo.gov.sg),TEST(https://test.api.myinfo.gov.sg),PRODUCT(https://api.myinfo.gov.sg)
SANDBOX使用最简单,直接调用该接口(https://sandbox.api.myinfo.gov.sg/com/v3/person-sample/{uinfin})就能获取用户信息,uinfin可以理解为用户ID,这些用户信息都是测试数据,可以通过这些数据了解myinfo的数据格式
TEST和PRODUCT可以看成一致的,因为流程上没有太大区别,下面以TEST举例
首选申请好myinfo的clientID、clientSecret以及我们自己网站的私钥证书和myinfo的509证书,我们自己网站的公钥证书需要提前配置在myinfo官网中这一步在申请clientID和clientSecret时一起完成。如果没有自己的账可以使用官方的测试账号和证书,这些在官网中可以获取。
1.GET方法调用{host}/com/v3/authorise获取授权URL
Query参数:client_id={clientID}&attributes={请求的用户数据key,使用,间隔}&purpose={请求原因}&state={随便生成个uuid,回调的时候会传回来}&redirect_uri={接收myinfo回调的地址}
具体有哪些用户数据能获取可以调用SANDBOX的API查看
redirect_uri是接收myinfo授权结果的地址,默认固定http://localhost:3001/callback,其他地址需要到myinfo的配置页面中填写并且和提交的证书域名一致
2.用户授权结束之后会调用redirect_uri,GET方法,返回两个Query参数:code,state
如果授权通过,则code不为空,否则code为null
3.授权通过,POST方法调用{host}/com/v3/token,获取token
Form表单内容如下
grant_type="authorization_code"
code=code
redirect_uri=redirect_uri
client_id=clientID
client_secret=clientSecretHeader内容如下
Content-Type=application/x-www-form-urlencoded
Cache-Control=no-cache
Authorization=authorization生成authorization
url = {host}/com/v3/token
body = Form表单的map对象
privateKeyCert = base64格式的私钥证书
authorization = generateAuthHeader(url, body, "POST", "application/x-www-form-urlencoded", clientID, privateKeyCert, clientSecret)
函数generateAuthHeader的java如下
public static String generateAuthHeader(String url, Map<String, String> params, String method, String strContentType, String appId, String keyCertBse64, String appSecret) {try {
String nonceValue = String.valueOf(SecureRandom.getInstance("SHA1PRNG").nextLong());
String timestamp = String.valueOf(System.currentTimeMillis());
Map<String, String> defaultApexHeaders = new HashMap<>();defaultApexHeaders.put("app_id", appId);
defaultApexHeaders.put("nonce", nonceValue);
defaultApexHeaders.put("signature_method", "RS256");
defaultApexHeaders.put("timestamp", timestamp);
if (method == "POST" && strContentType != "application/x-www-form-urlencoded") {params = new HashMap<>();
}
Map<String, String> baseParams = new TreeMap<>();baseParams.putAll(params);
baseParams.putAll(defaultApexHeaders);
String baseParamsString = String.format("%s&%s&%s", method.toUpperCase(), url, NDICommon.map2String(baseParams));
String privateKeyContent = new String(Base64Utils.decode(keyCertBse64));
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(KeyUtils.getRSAPrivateKey(privateKeyContent));
signature.update(baseParamsString.getBytes());
byte[] signedData = signature.sign();
String finalSign = Base64Utils.encode(signedData);
String apexHeader = "PKI_SIGN timestamp=\"" + timestamp +
"\",nonce=\"" + nonceValue +
"\",app_id=\"" + appId +
"\",signature_method=\"RS256\"" +
",signature=\"" + finalSign +"\"";
return apexHeader;
} catch (Exception e) {
Logger.error(e);
}
return StringUtils.EMPTY_STRING;
}
4、第三步中成功获取到的access_token不要马上使用,因为有个生效时间,一般等待几秒钟即可
5、根据myinfo的公钥证书从access_token中获取sub
java获取sub的代码如下
public static String verifyAndGet(String token, RSAPublicKey publicKey, String key) {
try {
if (publicKey == null) {Logger.error("JWTUtils.verifyAndGet invalid public key");
return null;
}
Algorithm algorithm = Algorithm.RSA256(publicKey, null);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return jwt.getClaim(key).asString();
} catch (Exception e) {
Logger.error(e);
}
return null;
}
6、用sub和access_token获取用户信息,GET方法调用{host}/com/v3/person/{sub}/
Query参数:client_id={clientId}&attributes={请求的用户数据key,使用,间隔}
Header内容如下
Cache-Control=no-cache
Authorization={authorization},Bearer {access_token}生成authorization
url = {host}/com/v3/person/{sub}/
body = Query参数的map对象
privateKeyCert = base64格式的私钥证书
authorization = generateAuthHeader(url, body, "GET", "", clientID, privateKeyCert, clientSecret)
最后解密返回的jwe数据就是用户信息了
String personJWT = JWEUtils.decrypt(jwe, KeyUtils.getRSAPrivateKey(privateKey));
return JWTUtils.verify(personJWT, KeyUtils.getRSAPublicKey(publicKey));
java代码如下
public static String decrypt(String jwe, RSAPrivateKey privateKey) {
try {
if (privateKey == null) {Logger.error("JWEUtils.decrypt invalid private key");
return null;
}
JWEObject jweObject = JWEObject.parse(jwe);
JWEDecrypter decrypter = new RSADecrypter(privateKey);
jweObject.decrypt(decrypter);
return jweObject.getPayload().toString().replace("\"", "");
} catch (Exception e) {
Logger.error(e);
}
return null;
}
public static String verify(String token, RSAPublicKey publicKey) {
try {
if (publicKey == null) {Logger.error("JWTUtils.verify invalid public key");
return null;
}
Algorithm algorithm = Algorithm.RSA256(publicKey, null);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return JsonUtils.toJson(parseJWT(jwt));
} catch (Exception e) {
Logger.error(e);
}
return null;
}