此文分為幾個部分:
[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 程式下載及安裝
RP要由OP取得ACCESS TOKEN
必要條件
1. RP 要先向 OP取得 client_id, client_secret,由於認證網站採用 Basic auth,所以還需要有 auth_secret
2. RP 要先設定 redirect_url,認證後回傳到此網址
取得 CODE
將網址導向 oidc認證主機,他的網址是,在 [PHP] OPENID CONNECT #0 簡介及取得URL@Axer's World 中有取得authorization_endpoint
https://oidc.tanet.edu.tw/oidc/v1/azp
其中所代的參數為:
clientid 需申請,由op提供
scope 定義 access token可以存取的權限 openid(必要), openid2(選項), email(選項), profile(選項)
response_type code
redirect_uri 需申請時設定,且urlencoded
state 必要,RP需由帶回來的值驗證SESSION連續狀態
nonce 必要,可用來防止權杖重新取得攻擊
一個連結的範例(認證方法是GET)
https://oidc.tanet.edu.tw/oidc/v1/azp?response_type=code&client_id=d8170c2861d20da77c5839bc71ea4937&redirect_uri=http%3A%2F%2Fexample.com%2Fopenidconnect%2Fcallback.php&scope=openid+email+profile&state=8143249&nonce=NSFSTW
程式記住state值並提供連結給使用者點擊,執行畫面
使用者點擊此連結後會導向此網址後的認證範例畫面
使用者輸入錯誤的範例,帳密驗證錯誤的話無法把資料傳回。
使用者輸入帳密認證成功後會導回RP的redirect_uri,GET帶回參數:
code 接下來取得access token用
state 檢查session的連續性
範例認證後OP轉址到redirect_uri並帶回code及state值
http://example.com/openidconnect/callback.php?code=br2qjcGi5imfua29thT_0Qr9JAbLXNT0zOs_0DnwX0w&state=8143249
寫到這裡我想要貼這張同事傳來的圖片,程式來不及寫了還得寫文件
PHP
config.php
<?php // RP申請獲得 define('CLIENT_ID', '3b0d2d618fab2----e08ca605e1a74a'); define('CLIENT_SECRET', 'cfc3d40dee3657e----31f1723c4a0804ca0e'); define('AUTH_SECRET', 'dWhvby50d0BnbWFpbC5jb20='); define('REDIR_URI0', 'http://opneid.example.com/callback.php'); define('WELL_KNOWN_URL', 'https://oidc.tanet.edu.tw/.well-known/openid-configuration'); // 預設0由設定檔的URL決定;設定為1則每次皆由WELL_KNOWN取回END POINT URL define('DYNAMICAL_ENDPOINT', 0); // DYNAMICAL_ENDPOINT設為0下方需填寫 define('AUTH_ENDPOINT', 'https://oidc.tanet.edu.tw/oidc/v1/azp'); define('TOKEN_ENDPOINT', 'https://oidc.tanet.edu.tw/oidc/v1/token'); define('USERINFO_ENDPOINT', 'https://oidc.tanet.edu.tw/oidc/v1/userinfo'); // PROFILE URL define('PROFILE_ENDPOINT', 'https://oidc.tanet.edu.tw/moeresource/api/v1/oidc/profile');
openidconnect/index.php
<?php include "config.php"; include "library.class.php"; $obj= new openid(); $_SESSION['azp_state']=rand(0,9999999); //隨機產生state值 $_SESSION['nonce']=isset($_SESSION['nonce'])? $_SESSION['nonce']:base64_encode($_SESSION['azp_state']); $auth_ep=AUTH_ENDPOINT; if(DYNAMICAL_ENDPOINT){ $auth_ep=$ep->getEndPoint()->authorization_endpoint; } $link = $auth_ep . "?response_type=code&client_id=". CLIENT_ID . "&redirect_uri=".REDIR_URI0 ."&scope=openid+email+profile&state=".$_SESSION['azp_state']. "&nonce=".$_SESSION['nonce']; ?> <!doctype html> <html lang="zh-TW"> <head> <meta charset="utf-8" /> </head> <body> <a href="<?php echo $link ?>">使用教育部OPENID認證</a> </body> </html>
openidconnect/callback.php
$code= $_GET['code']; $state= $_GET['state']; //驗證 $state if( !isset($_GET['code']) || !isset($_GET['state'])){ die ("認證伺服器回傳結果失敗!"); } if( strcmp($state, $_SESSON['azp_state'])){ die ("錯誤的認證狀態,請重新嘗試!"); } //取回access token include "config.php"; include "library.class.php"; $obj= new openid(); $token_ep=TOKEN_ENDPOINT; if(DYNAMICAL_ENDPOINT){ $token_ep=$ep->getEndPoint()->token_endpoint; } $acctoken= $obj->getAccessToken($token_ep ,$code, REDIR_URI0); if( !$acctoken || !isset($acctoken->access_token) ) { die ("無法取得ACCESS TOKEN"); } // 把access token記到session中 print $_SESSION['access_token']= $acctoken->access_token;
第23行執行取回access token的函式,待下一篇說明,取回的access token記到SESSION中,待後面要取回userinfo使用