validate([ 'code' => ['required', 'string'], ]); $appId = (string) config('wechat.app_id'); $secret = (string) config('wechat.app_secret'); if ($appId === '' || $secret === '') { return response()->json(['message' => '服务端未配置微信公众号 AppId/AppSecret'], 503); } $tokenRes = Http::timeout(15) ->get('https://api.weixin.qq.com/sns/oauth2/access_token', [ 'appid' => $appId, 'secret' => $secret, 'code' => $data['code'], 'grant_type' => 'authorization_code', ]) ->json(); if (! empty($tokenRes['errcode'])) { throw ValidationException::withMessages([ 'code' => [$tokenRes['errmsg'] ?? '微信 code 无效或已使用'], ]); } $accessToken = (string) ($tokenRes['access_token'] ?? ''); $openid = (string) ($tokenRes['openid'] ?? ''); if ($accessToken === '' || $openid === '') { return response()->json(['message' => '微信未返回 access_token'], 422); } $unionid = $tokenRes['unionid'] ?? null; $info = Http::timeout(15) ->get('https://api.weixin.qq.com/sns/userinfo', [ 'access_token' => $accessToken, 'openid' => $openid, 'lang' => 'zh_CN', ]) ->json(); if (! empty($info['errcode'])) { $info = []; } if ($unionid === null && ! empty($info['unionid'])) { $unionid = $info['unionid']; } $wu = WechatUser::query()->updateOrCreate( ['openid' => $openid], [ 'unionid' => $unionid, 'nickname' => $info['nickname'] ?? null, 'avatar_url' => $info['headimgurl'] ?? null, ] ); $plain = $wu->createToken('wechat-h5')->plainTextToken; return response()->json([ 'token' => $plain, 'user' => [ 'id' => $wu->id, 'nickname' => $wu->nickname, 'avatar_url' => $wu->avatar_url, ], ]); } }