WechatController.php 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. <?php
  2. namespace App\Http\Controllers\Account;
  3. use App\Cache\WechatStateCache;
  4. use App\Libs\ApiResponse;
  5. use App\Services\Account\AccountService;
  6. use App\Services\Account\WechatService;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Routing\Controller as BaseController;
  9. class WechatController extends BaseController
  10. {
  11. use ApiResponse;
  12. protected $wechatService;
  13. protected $accountService;
  14. public function __construct(
  15. WechatService $wechatService,
  16. AccountService $accountService
  17. ) {
  18. $this->wechatService = $wechatService;
  19. $this->accountService = $accountService;
  20. }
  21. /**
  22. * 微信扫码登录入口:生成 state 后跳转到微信官方二维码页
  23. *
  24. * @return \Illuminate\Http\RedirectResponse
  25. */
  26. public function login()
  27. {
  28. $state = md5(uniqid((string)mt_rand(), true));
  29. WechatStateCache::set($state, (int)config('wechat.state_ttl', 600));
  30. return redirect()->away($this->wechatService->buildAuthUrl($state));
  31. }
  32. /**
  33. * 微信扫码回调:换取用户、注册/登录并带回 token
  34. *
  35. * @param Request $request
  36. * @return \Illuminate\Http\RedirectResponse
  37. */
  38. public function callback(Request $request)
  39. {
  40. $code = trim((string)$request->get('code', ''));
  41. $state = trim((string)$request->get('state', ''));
  42. $frontend = (string)config('wechat.web.frontend_redirect', '/');
  43. try {
  44. if ($state === '' || !WechatStateCache::pull($state)) {
  45. throw new \RuntimeException('登录已失效,请重新扫码');
  46. }
  47. if ($code === '') {
  48. throw new \RuntimeException('未获取到微信授权码');
  49. }
  50. list($uid, $isNew) = $this->wechatService->loginByCode($code);
  51. $tokenData = $this->accountService->issueTokenForUser((int)$uid);
  52. return redirect()->away($this->appendQuery($frontend, [
  53. 'd-token' => $tokenData['token'],
  54. 'uid' => (int)$uid,
  55. 'is_new' => $isNew ? 1 : 0,
  56. ]));
  57. } catch (\Throwable $e) {
  58. dLog('wechat')->info('wechat callback error', [$e->getMessage()]);
  59. return redirect()->away($this->appendQuery($frontend, [
  60. 'wechat_error' => $e->getMessage(),
  61. ]));
  62. }
  63. }
  64. /**
  65. * 追加 query 参数
  66. *
  67. * @param string $url
  68. * @param array $params
  69. * @return string
  70. */
  71. private function appendQuery(string $url, array $params): string
  72. {
  73. $separator = strpos($url, '?') === false ? '?' : '&';
  74. return $url . $separator . http_build_query($params);
  75. }
  76. }