WechatIdentityProvider.php 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. <?php
  2. declare(strict_types=1);
  3. namespace app\miniapi\auth;
  4. use app\miniapi\exception\ApiException;
  5. final class WechatIdentityProvider implements IdentityProvider
  6. {
  7. public function exchange(string $code): array
  8. {
  9. $appid = (string) config('mini_api.wechat_appid', '');
  10. $secret = (string) config('mini_api.wechat_secret', '');
  11. if ($appid === '' || $secret === '') {
  12. throw new ApiException(50301, '微信登录尚未配置', 503);
  13. }
  14. $url = 'https://api.weixin.qq.com/sns/jscode2session?' . http_build_query([
  15. 'appid' => $appid,
  16. 'secret' => $secret,
  17. 'js_code' => $code,
  18. 'grant_type' => 'authorization_code',
  19. ]);
  20. $ch = curl_init($url);
  21. curl_setopt_array($ch, [
  22. CURLOPT_RETURNTRANSFER => true,
  23. CURLOPT_CONNECTTIMEOUT => 5,
  24. CURLOPT_TIMEOUT => 10,
  25. CURLOPT_SSL_VERIFYPEER => true,
  26. CURLOPT_SSL_VERIFYHOST => 2,
  27. CURLOPT_FOLLOWLOCATION => false,
  28. ]);
  29. $raw = curl_exec($ch);
  30. $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  31. curl_close($ch);
  32. if ($raw === false || $status !== 200) {
  33. throw new ApiException(50302, '微信登录服务暂时不可用', 503);
  34. }
  35. $data = json_decode($raw, true);
  36. if (!is_array($data) || empty($data['openid']) || !is_string($data['openid']) || strlen($data['openid']) > 128) {
  37. throw new ApiException(40102, '微信登录凭据无效,请重新登录', 401);
  38. }
  39. // session_key and unionid are deliberately neither returned nor logged.
  40. return [
  41. 'appid' => $appid,
  42. 'openid' => $data['openid'],
  43. ];
  44. }
  45. }