增加google授权Oauth2.0

This commit is contained in:
hgc 2024-12-20 18:08:48 +08:00
parent ba50f79c55
commit 9da48235e3
5 changed files with 245 additions and 1 deletions

View File

@ -87,7 +87,7 @@ class AdController
{
return Json([
'code' => 0,
'msg' => date('Y-m-d'),
'msg' => 'ok',
'data' => $data,
]);
}

View File

@ -0,0 +1,105 @@
<?php
namespace app\controller;
use app\service\GoogleOAuthService;
use support\Request;
use support\Response;
use DI\Annotation\Inject;
class OAuthController
{
/**
* @Inject
* @var GoogleOAuthService
*/
private $googleOAuthService;
public function getAuthCode()
{
$authUrl = $this->googleOAuthService->getAuthUrl();
return $this->successResponse([
'url' => $authUrl,
]);
}
public function handleCallback(Request $request)
{
// $state = $request->input('state'); // 从Google回调中获取state
$code = $request->input('code'); // 授权码
// 验证state值是否与保存的值一致
// if ($state !== $_SESSION['oauth_state']) {
// if ($state !== '7a7a9edad5b48c127b7c14fabe39fae0') {
// return $this->errorResponse(400, 'Invalid state parameter');
// }
// state值验证通过继续处理授权码
$googleOAuthService = new GoogleOAuthService();
$tokens = $googleOAuthService->getRefreshToken($code);
return $this->successResponse($tokens);
}
public function getRefreshToken(Request $request)
{
$authCode = $request->input('code');
// $state = $request->input('state'); // 从Google回调中获取state
// 验证state值是否与保存的值一致
// if ($state !== $_SESSION['oauth_state']) {
// return $this->errorResponse(400, 'Invalid state parameter');
// }
$googleOAuthService = new GoogleOAuthService();
$tokens = $googleOAuthService->getRefreshToken($authCode);
if (!isset($tokens['refresh_token'])) {
return $this->successResponse($tokens);
}
// 保存refresh token到数据库
// $googleOAuthService->saveRefreshToken($tokens['refresh_token'], $tokens['access_token'], $request->user_id);
$googleOAuthService->saveRefreshToken($tokens['refresh_token'], $tokens['access_token']);
return $this->successResponse($tokens);
}
public function useRefreshToken(Request $request)
{
$refreshToken = $request->input('refresh_token');
$googleOAuthService = new GoogleOAuthService();
$newAccessToken = $googleOAuthService->useRefreshToken($refreshToken);
return $this->successResponse(['access_token' => $newAccessToken]);
}
public function revokeRefreshToken(Request $request)
{
$accessToken = $request->input('token'); //access token
$googleOAuthService = new GoogleOAuthService();
$googleOAuthService->revokeToken($accessToken);
return $this->successResponse(['deleted' => 'success']);
}
// 可以加入一些公共方法
protected function successResponse($data): Response
{
return Json([
'code' => 0,
'msg' => 'ok',
'data' => $data,
]);
}
protected function errorResponse($code, $message, $data = []): Response
{
return Json([
'code' => $code,
'msg' => $message ?: 'error',
'data' => $data
]);
}
}

10
app/model/ThirdUser.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace app\model;
use think\Model;
class ThirdUser extends Model
{
protected $table = 'bps.bps_third_user';
protected $primaryKey = 'id';
}

View File

@ -0,0 +1,120 @@
<?php
namespace app\service;
use GuzzleHttp\Client;
use think\facade\Db as ThinkDb;
class GoogleOAuthService
{
public function getAuthUrl()
{
$clientId = getenv('GOOGLE_CLIENT_ID');
$redirectUri = getenv('GOOGLE_REDIRECT_URI');
$scope = 'https://www.googleapis.com/auth/adwords';
$responseType = 'code';
$accessType = 'offline';
// $state = 'state_parameter_passthrough_value'; // 可选保护防止CSRF
// 生成随机的state参数防止CSRF攻击
// $state = bin2hex(random_bytes(16)); // 生成一个随机字符串
// 将state保存到会话或数据库中稍后验证
// $_SESSION['oauth_state'] = $state; // 使用PHP会话来保存state
// $authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&state=$state";
$authUrl = "https://accounts.google.com/o/oauth2/v2/auth?client_id=$clientId&redirect_uri=$redirectUri&scope=$scope&response_type=$responseType&access_type=$accessType";
return $authUrl;
}
public function getRefreshToken($authCode)
{
$client = new Client();
$response = $client->post('https://oauth2.googleapis.com/token', [
'form_params' => [
'code' => $authCode,
'client_id' => getenv('GOOGLE_CLIENT_ID'),
'client_secret' => getenv('GOOGLE_CLIENT_SECRET'),
'redirect_uri' => getenv('GOOGLE_REDIRECT_URI'),
'grant_type' => 'authorization_code',
],
]);
return json_decode($response->getBody(), true);
}
public function saveRefreshToken($refreshToken, $accessToken)
{
// 使用ThinkORM保存数据到bps_third_user表
// $thirdUser = new \App\Models\ThirdUser();
// $thirdUser->access_token = $accessToken;
// $thirdUser->is_default = true;
// $thirdUser->random_code = bin2hex(random_bytes(16)); // 生成随机码
// $thirdUser->third_type = 'google';
// $thirdUser->user_id = $userId;
// $thirdUser->save();
$data = [
'access_token' => $refreshToken,
'is_default' => 't',
'third_type' => 'google',
];
$tableName = 'bps_third_user';
$tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName;
$sql = "
INSERT INTO {$tableName}
(access_token, is_default, third_type)
VALUES (:access_token, :is_default, :third_type)
ON CONFLICT (user_id)
DO UPDATE SET
access_token = EXCLUDED.access_token,
is_default = EXCLUDED.is_default,
";
// $sql = "
// INSERT INTO {$tableName}
// (access_token, is_default, random_code, third_type, user_id, facebook_user_id)
// VALUES (:access_token, :is_default, :random_code, :third_type, :user_id, :facebook_user_id)
// ON CONFLICT (user_id)
// DO UPDATE SET
// access_token = EXCLUDED.access_token,
// is_default = EXCLUDED.is_default,
// random_code = EXCLUDED.random_code,
// third_type = EXCLUDED.third_type,
// ";
ThinkDb::execute($sql, $data);
}
public function revokeToken($accessToken)
{
$client = new Client();
$client->post('https://oauth2.googleapis.com/revoke', [
'form_params' => [
'token' => $accessToken,
],
]);
// 在数据库中删除或标记该`refresh_token`为无效
// \App\Models\ThirdUser::where('access_token', $refreshToken)->delete();
}
public function useRefreshToken($refreshToken)
{
$client = new Client();
$response = $client->post('https://oauth2.googleapis.com/token', [
'form_params' => [
'refresh_token' => $refreshToken,
'client_id' => getenv('GOOGLE_CLIENT_ID'),
'client_secret' => getenv('GOOGLE_CLIENT_SECRET'),
'grant_type' => 'refresh_token',
],
]);
$data = json_decode($response->getBody(), true);
return $data['access_token'];
}
}

View File

@ -14,6 +14,7 @@
//use app\controller\IndexController;
use app\controller\AdController;
use app\controller\OAuthController;
use app\controller\GoogleAdsController;
use Webman\Route;
@ -48,6 +49,14 @@ Route::group('/googleads', function () {
Route::group('/adgroup', function () {
Route::post('/export', [AdController::class, 'exportGroupsToExcel']);
});
Route::group('/auth', function () {
Route::get('/code', [OAuthController::class, 'getAuthCode']);
Route::post('/callback', [OAuthController::class, 'handleCallback']);
Route::post('/refresh_token_get', [OAuthController::class, 'getRefreshToken']);
Route::post('/refresh_token_use', [OAuthController::class, 'useRefreshToken']);
Route::post('/refresh_token_revoke', [OAuthController::class, 'revokeRefreshToken']);
});
});
Route::group('/campaign', function () {