此文分為幾個部分:
[PHP] OPENID CONNECT #0 簡介及取得URL
[PHP] OPENID CONNECT #1 取得ACCESS TOKEN
[PHP] OPENID CONNECT #2 取得USERINFO及PROFILE
[PHP] OPENID CONNECT #3 驗證id_token
[PHP] OPENID CONNECT #4 程式下載及安裝
在#1 取得ACCESS TOKEN #2 取得USERINFO及PROFILE兩篇文件中ACCESS TOKEN取回時也有得到 id_token的欄位,id_token的欄位是JSON Web Token(JWT)的格式
id_token介紹
1. BASE64 編碼
2. 分成三個部分,中間用 '.'作區分
3. 一個JWT範例。其中第1部分(青色)寫的是簽章方式,第2部分(綠色)是OP送出來部分的欄位CLAIMS,第3部分(黃色)是由第1、第2兩部分簽章後的結果,2進位內容
經由BASE64 解碼後內容範例為:
4. 欄位說明
alg 簽章方式,採用 RS256方式簽章,對稱金鑰
sub subject 帳號唯一識別碼
aud audience 聽眾就是你的client_id
iss issuer id_token發行者
exp 有效時間 timestamp
iat issue at time 簽發時間 timestamp iat+3600=exp
產生公鑰
和SSL有關的,可用來驗證ID TOKEN的資料在OPENID CONNECT #0 簡介及取得URL此文中有:
"jwks_uri" : "https://oidc.tanet.edu.tw/oidc/v1/jwksets"
其內容為
取其中的 use:"sig"的key值module(n)和exponents(e)來演算公錀(public key)
PHP
使用modulus(n)和exponent(e)來產生金鑰, 需要安裝套件phpseclib,程式碼
<?php
use phpseclib\Crypt\RSA;
use phpseclib\Math\BigInteger;
//取回access token
include "config.php";
include "library.class.php";
include('./vendor/autoload.php'); //驗證 id_token 所需套件
$obj= new openid();
$jwks_uri=JWKS_URI;
if(DYNAMICAL_ENDPOINT){
$jwks_uri=$ep->getEndPoint()->jwks_uri;
}
$jd = $obj->getModnExp($jwks_uri);
if( !$jd) {
die ("無法取得 USER INFO");
}
$e= $jd['keys'][0]['e'];
$n= $jd['keys'][0]['n'];
// 取得public key,需安裝套件
// https://github.com/phpseclib/phpseclib
$rsa = new RSA();
$nx = new BigInteger($obj->urlsafeB64Decode($n), 256);
$ex = new BigInteger($obj->urlsafeB64Decode($e), 256);
$rsa->loadKey(
array(
'e' => $ex,
'n' => $nx
)
);
$pubkey= $rsa->getPublicKey();
其中 $pubkey輸出結果
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmzzA8UMrmiFxqA4fCQWx
/BGwxkpZ5QrTBkQkHBpQ0piISte7VS+xbvcgFdrT6Gzsq+f36HgSO8pwHPkioJak
lo/4ro/VgIWStBd2Jjd6kDEa5Kzbyc/9/FRDtjXA/giiMwTIqHQwYsAWgOrNw7a/
J9DGOPhtwfnHNRu30iAtWMga3iGh1vcWOVSZyl/xzFBuLb0hYdaKG8beJ+qp+hiS
QqxCAcEapeXoMwAVomlpaQDsHwyNigW+CxTVSNfbZxLCmMabEPqBJSnAkiHaSrv8
/ATBHi+LAF3JIIzD5qGUgp1vVDVKEm9HrlIvOO7spyyCw/I4CdSZXS2vERyMSTit
vQIDAQAB
-----END PUBLIC KEY-----
接下來要由public key來驗證 id_token
驗證id_token
取得 public key後就可驗證 id_token, 需要安裝套件namshi/jose,這個套件對於PHP>=7.0有支持上的問題,會出現錯誤:
Fatal error: Uncaught InvalidArgumentException: phpseclib 1.0.0(LTS), even the latest 2.0.0, doesn't support PHP7 yet in /.../vendor/namshi/jose/src/Namshi/JOSE/JWS.php:xxx
需要修改原始碼 JWS.php把限制改掉
修改 ./vendor/namshi/jose/src/Namshi/JOSE/JWS.php 把第41-43行註解

PHP
驗證 id_token
// 驗證id token,需安裝套件
// composer require namshi/jose
$id_token = $_SESSION['id_token'];
$JWS= new JWS(array(),'SecLib');
$jws = $JWS->load($id_token);
$p=$jws->getPayload();; //取得payload
if ($jws->verify($pubkey, 'RS256')) {
echo sprintf("ID_TOKEN驗證通過,USER UNIQUE ID= #%s", $p['sub']);
}else{
echo "ID_TOKEN驗證失敗";
}
執行結果

參考資料
[1] 驗證JWT https://jwt.io/
[2] https://jwt.io/introduction/
[3] http://phpseclib.sourceforge.net/rsa/intro.html
[4] https://stackoverflow.com/questions/16993838/openssl-how-can-i-get-public-key-from-modulus