本文详细讲解如何在 php 技术栈(特别是 slim 框架)中集成 azure ad b2c,涵盖注册应用、配置 openid connect 认证、令牌验证及部署要点,提供可落地的生产级实现路径。
Azure AD B2C 是面向消费者身份管理的云服务,特别适合需要支持多租户注册、社交登录(如 Google、Microsoft)、与 Dynamics 365 CE 深度集成的客户门户场景。尽管官方示例多基于 Laravel,但其核心协议(OpenID Connect)完全与框架无关——这意味着 Slim 等轻量级 PHP 框架同样可以高效、安全地接入。
Azure 门户配置
协议层对接(非框架依赖)
使用标准 OpenID Connect 协议完成三阶段交互:
Slim 框架集成示例(关键片段)
// routes.php use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request;
$app->get('/login', function (Request $request, Response $response) { $authUrl = sprintf( 'https://www./link/ce6bea6bedc68b2cc93817a072dddafd?' . 'client_id=%s&response_type=code&redirect_uri=%s&response_mode=query&scope=openid+profile&nonce=%s&state=%s', $_ENV['B2C_TENANT'], $_ENV['B2C_TENANT'], $_ENV['B2C_POLICY'], urlencode($_ENV['B2C_CLIENT_ID']), urlencode($_ENV['B2C_REDIRECT_URI']), bin2hex(random_bytes(16)), bin2hex(random_bytes(16)) ); return $response->withStatus(302)->withHeader('Location', $authUrl); });
$app->get('/callback', function (Request $request, Response $response) { $code = $request->getQueryParam('code'); if (!$code) { return $response->withStatus(400)->write('Missing authorization code'); }
// Exchange code for tokens
$tokenResponse = file_get_contents('https://' . $_ENV['B2C_TENANT'] . '.b2clogin.com/' .
$_ENV['B2C_TENANT'] . '.onmicrosoft.com/' . $_ENV['B2C_POLICY'] . '/oauth2/v2.0/token', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'content' => http_build_query([
'client_id' => $_ENV['B2C_CLIENT_ID'],
'client_secret' => $_ENV['B2C_CLIENT_SECRET'],
'code' => $code,
'redirect_uri' => $_ENV['B2C_REDIRECT_URI'],
'grant_type' => 'authorization_code'
])
]
]));
$tokens = json_decode($tokenResponse, true);
if (!isset($tokens['id_token'])) {
return $response->withStatus(401)->write('Token exchange failed');
}
// Validate ID token (using firebase/php-jwt)
$jwks = file_get_contents("https://{$_ENV['B2C_TENANT']}.b2clogin.com/{$_ENV['B2C_TENANT']}.onmicrosoft.com/{$_ENV['B2C_POLICY']}/discovery/v2.0/keys");
$keys = json_decode($jwks, true)['keys'];
$jwt = \Firebase\JWT\JWT::decode($tokens['id_token'], new \Firebase\JWT\JWK($keys), ['RS256']);
// Store session or JWT in Slim container, then redirect to dashboard
$_SESSION['user'] = (array) $jwt;
return $response->withStatus(302)->withHeader('Location', '/dashboard');});

### ⚠️ 注意事项与最佳实践 - **绝不硬编码密钥**:`client_secret` 必须通过环境变量(如 `.env` + `vlucas/phpdotenv`)加载,禁止提交至 Git。 - **强制 HTTPS**:所有重定向 URI 必须为 `https://`(本地开发可临时用 `http://localhost`,但生产环境必须 HTTPS)。 - **PKCE 推荐**:若面向公共客户端(如单页应用),应弃用 `client_secret`,改用 PKCE 流程增强安全性。 - **状态(state)与随机数(nonce)校验**:防止 CSRF 和重放攻击,务必在发起请求和回调时双向比对。 - **JWKS 缓存**:避免每次验证都远程获取公钥,建议本地缓存(如 Redis)并设置合理 TTL(如 24 小时)。 - **Dynamics CE 集成延伸**:获取用户 `object_id` 后,可调用 Dynamics Web API(`https://.api.crm.dynamics.com/api/data/v9.2/systemusers`)关联客户数据,需配置 B2C 与 Dynamics 的应用权限。 通过以上结构化实现,PHP + Slim 应用可完全剥离用户认证逻辑,专注业务价值,同时无缝对接 Azure 生态(含 Dynamics 365 CE)。官方 GitHub 示例虽基于旧版 Laravel,但其协议层代码(尤其是 OIDC 流程与 JWT 验证)可直接复用或迁移至 Slim,无需额外 SDK。