Я пытаюсь использовать клиент OAuth2 League , чтобы пользователи могли аутентифицировать мое Laravel веб-приложение для назначения встреч в своем календаре. ПРИМЕЧАНИЕ. Я не пытаюсь разрешить пользователям входить на мой сайт или проходить аутентификацию на моем сайте с помощью OAuth! Я просто хочу, чтобы пользователи могли добавлять встречи в свои собственные календари.
Я в основном следую схеме, описанной здесь: https://github.com/thephpleague/oauth2-google и создал один контроллер (называемый OauthController
одним методом, redirectGoogle
. Мой маршрут перенаправления (который зарегистрирован в Google) - https://example.com/oauth2/google
. Когда я попадаю в эту конечную точку в моем приложении Laravel, я перенаправляюсь в Google, чтобы разрешить моему приложению доступ к моему данные учетной записи, как и ожидалось, а затем перенаправляются обратно в конечную точку контроллера.
Однако каждый раз происходит сбой в строке exit('Invalid state');
.
Вот код метода контроллера:
public function redirectGoogle(Request $request)
{
$provider = new Google([
'clientId' => config('oauth.google_oauth_id'),
'clientSecret' => config('oauth.google_oauth_secret'),
'redirectUri' => 'https://example.com/oauth2/google',
]);
if (!empty($request->input('error'))) {
// Got an error, probably user denied access
dd($request->input('error'));
} elseif (empty($request->input('code'))) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
session(['oauth2state', $provider->getState()]);
Log::info('Storing provider state ' . session('oauth2state')); <-- Log entry exists so we know session value was written
header('Location: ' . $authUrl);
exit;
} elseif (empty($request->input('state')) || ($request->input('state') !== session('oauth2state', false))) {
Log::error($request->input('state') . ' did not equal stored value ' . session('oauth2state', false)); <-- Log entry exists
// State is invalid, possible CSRF attack in progress
exit('Invalid state'); <-- Breaks here
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $request->input('code')
]);
// Optional: Now you have a token you can look up a users profile data
try {
// We got an access token, let's now get the owner details
$ownerDetails = $provider->getResourceOwner($token);
// Use these details to create a new profile
dd('Hello %s!', $ownerDetails->getFirstName());
} catch (Exception $e) {
// Failed to get user details
dd('Something went wrong: ' . $e->getMessage());
}
// Use this to interact with an API on the users behalf
echo $token->getToken() . PHP_EOL;
// Use this to get a new access token if the old one expires
echo $token->getRefreshToken() . PHP_EOL;
// Unix timestamp at which the access token expires
echo $token->getExpires() . PHP_EOL;
dd();
}
}
Странно то, что сообщения журнала, указанные в приведенном выше коде, существуют, и значения совпадают (по крайней мере, он пытается записать первую переменную сеанса со значением, которое соответствовало бы значению второго файла журнала):
[2020-05-04 21:02:48] local.INFO: Storing provider state 4963a33bbd5bcf52d3e21c787f24bd7b
[2020-05-04 21:02:51] local.ERROR: 4963a33bbd5bcf52d3e21c787f24bd7b did not equal stored value <null>
Почему во второй раз в коде значение сеанса oauth2state
равно нулю, когда оно было успешно записано на первом l oop?
ПРИМЕЧАНИЕ: проблема, по-видимому, в том, что сеансы разные, что имеет смысл, но как этот сеанс может оставаться согласованным или иным образом поддерживать прямые данные?
[2020-05-05 15:25:06] local.INFO: Session id: bV7F5mNM69rJAVJNWK9ZD0rcoN284FxXvjNAmUiw
[2020-05-05 15:25:06] local.INFO: Storing provider state 7351b313b741df41a6be9a049f71db6b
[2020-05-05 15:25:10] local.INFO: Session id: VNiBxr1gYYIA9Nr11x9c4JJArHOiKQScEGh2jkuc
[2020-05-05 15:25:10] local.ERROR: 7351b313b741df41a6be9a049f71db6b did not equal stored value <null>
EDIT2: Я пробовал учебник здесь , в котором используется немного другой подход с использованием Laravel и библиотеки League Oauth - у него точно такая же проблема, сеанс Идентификатор в двух запросах различается, что означает, что вы никогда не сможете найти совпадение между ключами state
.