Angular+PHP项目Azure SSO添加证书认证的前后端实现步骤咨询
Azure SSO证书认证:Angular+PHP 具体实现步骤
一、Azure AD 前置配置(必须完成)
- 在Azure AD应用注册中上传证书公钥(替代客户端密钥),确保应用的API权限保留原有的
https://graph.microsoft.com/.default配置。
二、前端Angular 调整(几乎无改动)
证书认证属于后端与Azure的交互环节,前端授权码流程无需核心修改:
- 保持原有配置不变,继续通过授权码流程获取ID Token/Access Token。
- 确保传递给PHP后端的是完整的ID Token(而非仅Access Token),后端需用它做签名验证。
三、后端PHP 核心实现(证书认证核心)
3.1 准备证书文件
将Azure AD下载的证书公钥文件(.cer/.pem格式)放在PHP项目非Web可访问的安全目录下,设置严格文件权限(如chmod 600)。
3.2 验证前端传入的ID Token
使用firebase/php-jwt库结合证书验证Token签名与有效性:
- 安装依赖:
composer require firebase/php-jwt
- 验证逻辑代码:
use Firebase\JWT\JWT; use Firebase\JWT\Key; // 从前端请求获取ID Token $idToken = $_POST['id_token']; // 读取Azure证书公钥 $publicKey = file_get_contents('/path/to/secure-directory/azure-cert.pem'); try { // 验证Token并校验关键字段 $decoded = JWT::decode( $idToken, new Key($publicKey, 'RS256'), [ 'iss' => 'https://login.microsoftonline.com/{tenant-id}/v2.0', 'aud' => '{your-client-id}', // 应用注册的Client ID 'exp' => true // 校验过期时间 ] ); // 提取用户信息完成登录流程 $userInfo = [ 'userId' => $decoded->oid, 'email' => $decoded->email ?? $decoded->upn, 'name' => $decoded->name ]; echo json_encode(['success' => true, 'user' => $userInfo]); } catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); }
注意:
iss和aud必须与Azure应用注册配置完全匹配,否则验证失败。
3.3 可选:后端用证书调用Graph API
若后端需独立调用Graph API,可通过证书认证的客户端凭证流获取令牌:
$tenantId = '{your-tenant-id}'; $clientId = '{your-client-id}'; $certPath = '/path/to/secure-directory/private-cert.pem'; $certPassword = '{your-cert-password}'; // 证书有密码时填写 // 读取证书私钥 $privateKey = openssl_pkey_get_private( file_get_contents($certPath), $certPassword ); // 生成JWT断言 $now = time(); $assertion = [ 'aud' => "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token", 'iss' => $clientId, 'sub' => $clientId, 'exp' => $now + 3600, 'iat' => $now, 'jti' => uniqid() ]; // 签名断言 $jwt = JWT::encode($assertion, $privateKey, 'RS256'); // 请求Azure获取访问令牌 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'grant_type' => 'client_credentials', 'client_id' => $clientId, 'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', 'client_assertion' => $jwt, 'scope' => 'https://graph.microsoft.com/.default' ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $tokenData = json_decode($response, true); $accessToken = $tokenData['access_token'] ?? ''; // 使用令牌调用Graph API示例 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://graph.microsoft.com/v1.0/users/{target-user-id}'); curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $accessToken"]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $userData = curl_exec($ch); curl_close($ch);
四、关键注意事项
- 证书文件必须严格保密:私钥绝不能暴露到Web可访问目录,定期轮换证书。
- 完整校验Token字段:除签名外,必须校验
exp(过期时间)、nbf(生效时间)等字段,避免非法Token。
内容的提问来源于stack exchange,提问作者Lovitha
相关产品推荐
相关产品推荐

