$config['client_id'], 'redirect_uri' => $redirect_uri, 'response_type' => 'code', 'scope' => 'openid email profile', 'state' => $state, ]); } $oauth = $this->client($provider, $config, $redirect_uri); $scope = $provider === 'github' ? 'read:user user:email' : null; return (string) $oauth->getAuthUrl($redirect_uri, $state, $scope); } public function identity(string $provider, string $code, string $redirect_uri, string $state): array { $config = OAuthProviderCatalog::provider_config($provider); if (!$config || !$config['configured']) { throw new \RuntimeException(__('未配置此第三方登录平台', 'aksrt')); } if ($provider === 'google') { return $this->google_identity($config, $code, $redirect_uri); } $oauth = $this->client($provider, $config, $redirect_uri); $oauth->getAccessToken($state, $code, $state); if ($provider === 'qq') { $openid = (string) $oauth->getOpenID(); $info = (array) $oauth->getUserInfo(); return $this->normalize($provider, $openid, $info); } $info = (array) $oauth->getUserInfo(); if ($provider === 'github') { return $this->github_identity($oauth, $info); } return $this->normalize($provider, '', $info); } private function client(string $provider, array $config, string $redirect_uri) { switch ($provider) { case 'github': return new \Yurun\OAuthLogin\Github\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri); case 'gitee': return new \Yurun\OAuthLogin\Gitee\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri); case 'qq': return new \Yurun\OAuthLogin\QQ\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri); case 'weibo': return new \Yurun\OAuthLogin\Weibo\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri); case 'weixin': return new \Yurun\OAuthLogin\Weixin\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri); } throw new \RuntimeException(__('不支持的第三方登录平台', 'aksrt')); } private function github_identity($oauth, array $info): array { $email = ''; $email_verified = false; $response = $oauth->http->header('Authorization', ' token ' . $oauth->accessToken) ->get('https://api.github.com/user/emails') ->body(); $emails = json_decode((string) $response, true); foreach (is_array($emails) ? $emails : [] as $candidate) { if (!empty($candidate['primary']) && !empty($candidate['verified']) && is_email((string) ($candidate['email'] ?? ''))) { $email = sanitize_email((string) $candidate['email']); $email_verified = true; break; } } return [ 'provider' => 'github', 'provider_id' => (string) ($info['id'] ?? ''), 'username' => (string) ($info['login'] ?? ''), 'name' => (string) ($info['name'] ?? ''), 'email' => $email, 'email_verified' => $email_verified, 'avatar_url' => (string) ($info['avatar_url'] ?? ''), 'url' => (string) ($info['html_url'] ?? ''), 'bio' => (string) ($info['bio'] ?? ''), ]; } private function google_identity(array $config, string $code, string $redirect_uri): array { $response = wp_remote_post('https://oauth2.googleapis.com/token', [ 'timeout' => 15, 'redirects' => 2, 'body' => [ 'code' => $code, 'client_id' => $config['client_id'], 'client_secret' => $config['client_secret'], 'redirect_uri' => $redirect_uri, 'grant_type' => 'authorization_code', ], ]); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { throw new \RuntimeException(is_wp_error($response) ? $response->get_error_message() : __('Google token 获取失败', 'aksrt')); } $token = json_decode((string) wp_remote_retrieve_body($response), true); if (empty($token['access_token'])) { throw new \RuntimeException(__('Google token 获取失败', 'aksrt')); } $profile_response = wp_remote_get('https://openidconnect.googleapis.com/v1/userinfo', [ 'timeout' => 15, 'redirects' => 2, 'headers' => ['Authorization' => 'Bearer ' . $token['access_token']], ]); if (is_wp_error($profile_response) || wp_remote_retrieve_response_code($profile_response) !== 200) { throw new \RuntimeException(is_wp_error($profile_response) ? $profile_response->get_error_message() : __('Google 用户信息获取失败', 'aksrt')); } $info = json_decode((string) wp_remote_retrieve_body($profile_response), true); return [ 'provider' => 'google', 'provider_id' => (string) ($info['sub'] ?? ''), 'username' => (string) ($info['email'] ?? ''), 'name' => (string) ($info['name'] ?? ''), 'email' => sanitize_email((string) ($info['email'] ?? '')), 'email_verified' => !empty($info['email_verified']), 'avatar_url' => (string) ($info['picture'] ?? ''), 'locale' => (string) ($info['locale'] ?? ''), ]; } private function normalize(string $provider, string $provider_id, array $info): array { switch ($provider) { case 'gitee': return [ 'provider' => $provider, 'provider_id' => (string) ($info['id'] ?? ''), 'username' => (string) ($info['login'] ?? ''), 'name' => (string) ($info['name'] ?? ''), 'email' => sanitize_email((string) ($info['email'] ?? '')), 'email_verified' => false, 'avatar_url' => (string) ($info['avatar_url'] ?? ''), 'url' => (string) ($info['html_url'] ?? ''), 'bio' => (string) ($info['bio'] ?? ''), ]; case 'qq': return [ 'provider' => $provider, 'provider_id' => $provider_id, 'username' => (string) ($info['nickname'] ?? ''), 'name' => (string) ($info['nickname'] ?? ''), 'email' => '', 'email_verified' => false, 'avatar_url' => (string) ($info['figureurl_qq_2'] ?? $info['figureurl_2'] ?? $info['figureurl'] ?? ''), ]; case 'weibo': return [ 'provider' => $provider, 'provider_id' => (string) ($info['id'] ?? ''), 'username' => (string) ($info['screen_name'] ?? ''), 'name' => (string) ($info['name'] ?? ''), 'email' => '', 'email_verified' => false, 'avatar_url' => (string) ($info['avatar_large'] ?? $info['profile_image_url'] ?? ''), ]; case 'weixin': return [ 'provider' => $provider, 'provider_id' => (string) ($info['openid'] ?? ''), 'username' => (string) ($info['nickname'] ?? ''), 'name' => (string) ($info['nickname'] ?? ''), 'email' => '', 'email_verified' => false, 'avatar_url' => (string) ($info['headimgurl'] ?? ''), ]; } throw new \RuntimeException(__('不支持的第三方登录平台', 'aksrt')); } }