Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: logowanie do aplikacji za pomocą Tokena
Forum PHP.pl > Forum > PHP
inomi13
Do tej pory miałem zadanie cron, które wykonywało się raz dziennie i pobierało zawartość skrzynki za pomocą imap_open. W związku z wyłączeniem przez Microsoft uwierzytelnienia za pomocą hasła oraz że PHP nie posiada wbudowanej funkcji obsługującej Oauth2 w imapi'e skorzystałem z gotowego rozwiązania https://github.com/Webklex/php-imap i loguje się za pomocą Oauth2.

Problem polega na tym że ważność tokena to 1 godzina więc zadanie cron w tym wypadku odpada. Zrobiłem partyzanckie rozwiązanie tzn. loguje się przez przeglądarkę do konta Microsoft, następnie w sesji przesyłam otrzymany get adres e-mail oraz token do pliku konfiguracyjnego php-imap, a następnie dodałem meta
  1. <meta http-equiv="refresh" content = "3600" />
, które odświeża stronę przed wygaśnięciem tokena.

Proszę o sugestie jak powinno to sensownie działać, może odświeżenie tokena...
ohm
A nie ma zadnego endpointa api zebys mogl odpytac po token?
inomi13
Po wywołaniu poniższego kodu i zalogowaniu kontem Microsoft, wyciągam z URL'a token, który następnie obrabiam Curl'em, a następnie dekoduje je za pomocą json_decode.

Poniższy URL zawiera ważność tokena expires_in, więc bez odświeżenia tokena logout nastąpi po 1 godzine. Pytanie do znawców, w którą stronę iść aby wygenerować refresh tokens? Jeżeli ktoś ma jakieś przykłady to też chętnie przyjmę do analizy.


https://xxxxxxxxxxx?access_token=zb2Z0LmNvbSIsInV0aSI6Im9QRG9YajFrZVVDXXXXXX&token_type=Bearer&expires_in=4750&scope=https%3a%2f%2foutlook.office.com%2fIMAP.AccessAsUser.All+https%3a%2f%2foutlook.office.com%2fUser.Read&state=7f72451bd636d3c3d2030exxxxxxxx&session_state=4935654d-c68f-4df1-bc0d-xxxxxxxxxx



  1.  
  2. $appid = "XXXXXXXXXXXXXXXXXXX";
  3. $secret = "XXXXXXXXXXXXXXXXXXX";
  4. $loginUrl ="https://login.microsoftonline.com/XXXXXXXXXXXXXXXX/oauth2/v2.0/authorize";
  5.  
  6. $_SESSION['state'] = session_id();
  7.  
  8. echo '<a href="?action=login">Zaloguj</a>';
  9.  
  10. if($_GET['action'] == 'login')
  11. {
  12. $params = array ('client_id' => $appid,
  13.  
  14. 'redirect_uri' => 'https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  15.  
  16. 'response_type' => 'token',
  17.  
  18. 'scope' => 'https://outlook.office.com/IMAP.AccessAsUser.All',
  19.  
  20. 'state' => $_SESSION['state']);
  21.  
  22. header ('Location: '.$login_url.'?'.http_build_query ($params));
  23. }
vokiel
Zwykle w Oauth2 jest tak, że jak wygenerujesz access token to wraz z nim dostajesz też refresh token, który ma długi czas życia (albo nie wygasa do czasu odwołania). Za po mocą refresh tokena generujesz sobie nowy access token.
Autoryzację przez użytkownika robisz zwykle tylko raz.

Tu masz opisane
https://learn.microsoft.com/en-us/azure/act...-auth-code-flow
https://learn.microsoft.com/en-us/azure/act.../refresh-tokens
https://learn.microsoft.com/en-us/azure/act...op/v2-app-types
inomi13
I tutaj jest właśnie problem ponieważ nie mam pojęcia dlaczego w URL'u nie otrzymuje refresh_token. Po stronie Azure mam wszystko skonfigurowane według wytycznych Microsoft.
vokiel
Chyba nie czytałeś tej dokumentacji. Masz tam przecież ładny diagram z całym flow https://learn.microsoft.com/en-us/azure/act...op/v2-app-types

Wpierw sięgasz do /oauth2/authorize, potem do /oauth2/token
inomi13
Obecnie zrobiłem taki bypass. Loguję się do konta Microsoft zapisuje token oraz nazwę użytkownika w pliku nazwa.php, następnie cronem wywołuje skrypt, który sprawdza czy w pliku nazwa.php istnieje token i czy token jest zgodny. Wtedy następuje wywoływanie
  1. header ('Location: '.$login_url.'?'.http_build_query ($params))
ale już nie z tokenem pobranym z Url'a tylko pobranym z pliku. Co nie zmienia faktu że bez refresh_token po godzinie i tak nastąpi logout.
vokiel
Tylko po co robisz jakiś bypass skoro możesz zrobić to zgodnie z dokumentacją?

1. Generujesz link do logowania użytkownika: /authorize.
2. Dostajesz auth_code, którego używasz w requeście do /token
3. W odpowiedzi dostajesz access_token i refresh_token https://learn.microsoft.com/en-us/azure/act...sful-response-2
4. Zapisujesz sobie gdzieś tokeny wraz z czasem wygasania access_tokena.
5. Dalej w aplikacji sprawdzasz czy aktualny access_token jest jeszcze aktywny, jeśli tak to go używasz.
6. Jeśli nie, to bierzesz refresh_token i pobierasz nowy access_token.
inomi13
Zrobiłem tak jak sugerowałeś jednak nadal nie wiem dlaczego nie otrzymuje refresh_tokena

  1. $endpoint_authorize = 'https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/authorize';
  2. $endpoint_token = 'https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token';
  3. $redirect_uri = 'https://xxxxxxxxxxxxxxxxxxxxxxxxx.php';
  4.  
  5. $client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
  6. $client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxx';
  7.  
  8. $login = $endpoint_authorize.'?'.http_build_query([
  9. 'client_id' => $client_id,
  10. 'redirect_uri' => $redirect_uri,
  11. 'scope' => 'https://outlook.office.com/IMAP.AccessAsUser.All',
  12. 'response_type' => 'code',
  13. ]);
  14.  
  15. echo '<a href = "'.$login.'">Loguj</a>';
  16.  
  17. if(isset($_GET['code']))
  18. {
  19. $code = $_GET['code'];
  20.  
  21. $ch = curl_init();
  22. curl_setopt($ch, CURLOPT_URL,$endpoint_token);
  23. curl_setopt($ch, CURLOPT_POST, TRUE);
  24. curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']);
  25. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  26. curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
  27. 'code' => $code,
  28. 'client_id' => $client_id,
  29. 'client_secret' => $client_secret,
  30. 'redirect_uri' => $redirect_uri,
  31. 'grant_type' => 'authorization_code',
  32. ]));
  33. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  34. $response = curl_exec($ch);
  35. curl_close($ch);
  36.  
  37. echo '<pre>';
  38. print_r($response);
  39. echo '</pre>';
  40. }


Wynik dostaje:
"token_type":"Bearer",
"scope":"https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/User.Read",
"expires_in":3749,
"ext_expires_in":3749,
"access_token":"eyw......."


Ponowne odświeżenie strony daje wynik

{"error":"invalid_grant","error_description":"AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.\r\nTrace ID: xxxx-6c31-40c7-aa47-74b745582300\r\nCorrelation ID: xxxxx-8ecd-40da-a2d4-132f3be38b0a\r\nTimestamp: 2022-11-12 19:30:06Z","error_codes":[54005],"timestamp":"2022-11-12 19:30:06Z","trace_id":"xxxxx-6c31-40c7-aa47-74b745582300","correlation_id":"xxxxx-8ecd-40da-a2d4-132f3be38b0a"}

Znalazłem rozwiązanie mojego problemu, który polegał na złym ustawieniu zakresu tzn. jeżeli chcemy otrzymać refresh_token to zakres musi kończyć się offline_access. Oczywiście dostęp do offline_access musi być również ustawiony po stronie Azure.
ZenekN
o jaki zakres chodzi ?
viking
O scope.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.