Я пытаюсь войти в Azure B2C с помощью Laravel, сейчас я на полпути.
Часть Laravel — это API, а клиент — в Angular. Я планировал сделать весь процесс на BE. Когда пользователь нажимает «Войти с помощью Microsoft», он перенаправляется на серверную страницу BE, и я делаю волшебство на BE. В итоге хочу сделать редирект на какую-нибудь FE страницу и прописать токен доступа в куке.
Я определил два маршрута web.php (на стороне сервера). Первый предназначен для перенаправления на логин Azure, а второй — для обратного вызова.
Вот код:
public function redirect()
{
$length = mt_rand(43, 128);
$bytes = random_bytes($length);
$codeVerifier = rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
$state = Str::random(40);
$query = http_build_query([
'p' => 'B2C_1A_SIGNIN',
'client_id' => config('services.azureadb2c.client_id'),
'redirect_uri' => config('services.azureadb2c.redirect'),
'response_type' => 'code',
'scope' => 'openid',
'state' => $state,
'prompt' => 'login',
'code_challenge' => $this->generateCodeChallenge($codeVerifier),
'code_challenge_method' => 'S256',
]);
session(['state' => $state, 'code_verifier' => $codeVerifier]);
return redirect('https://' . config('services.azureadb2c.domain') . '.b2clogin.com/' . config('services.azureadb2c.domain') . '.onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/authorize?' . $query);
}
public function callback(Request $request)
{
$client = new Client();
$response = $client->post("https://" . config('services.azureadb2c.domain') . ".b2clogin.com/" . config('services.azureadb2c.domain') . ".onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/token?p=B2C_1A_SIGNIN", [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => config('services.azureadb2c.client_id'),
'client_secret' => config('services.azureadb2c.client_secret'),
'code' => $request->get('code'),
'redirect_uri' => config('services.azureadb2c.redirect'),
'code_verifier' => session('code_verifier'),
'scope' => 'openid',
],
]);
var_dump(json_decode($response->body()));
exit;
}
private function generateCodeChallenge($codeVerifier) {
$hash = hash('sha256', $codeVerifier, true);
$codeChallenge = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
return $codeChallenge;
}
Здесь я столкнулся со следующей проблемой. Перенаправление работает хорошо, пользователь перенаправляется правильно, и он может правильно ввести учетные данные и все такое. В конце обратного вызова я получаю код авторизации, но когда я делаю запрос POST для получения токена доступа, я получаю следующую ошибку
`400 Bad Request` response: {"error":"invalid_grant","error_description":"AADB2C90085: The service has encountered an internal error. Please reauthe (truncated...)
У вас есть идеи, что может вызвать эту ошибку?
@AnandSowmithiran Я видел этот пример, но он не имеет отношения к моему варианту использования. Этот пример содержит неявный поток, который возвращает токен доступа без кода авторизации. В моем случае я хочу войти в систему с помощью OpenID Connect и PKCE.
Полученная вами ошибка указывает на то, что предоставленной вами «области действия» недостаточно для возврата токена идентификатора.
@Ананд спасибо. Что я должен сделать, чтобы попытаться исправить это? Единственная поддерживаемая область — «openid», и я использую ее. Здесь я не получаю токен ID. На первом этапе я получаю только код авторизации, а затем передаю его, чтобы получить токен доступа.
Попробуйте передать идентификатор клиента также как одно значение области вместе с openid
, просто подсказка из Learn.microsoft.com/en-us/azure/active-directory-b2c/…
не помогло, пробовал разные варианты.
Я попытался воспроизвести то же самое в своей среде через Postman и получил следующие результаты:
Я зарегистрировал одно приложение Azure AD B2C, выбрав SPA в URI перенаправления, как показано ниже:
Я выполнил приведенный ниже код C# от Bac Hoang [MSFT] из этого блога и успешно получил значения code_challenge
и code_verifier
, как показано ниже:
using IdentityModel;
using System.Security.Cryptography;
using System.Text;
namespace PKCEConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var random = new Random();
int cvlength = random.Next(43, 128);
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
var codeVerifier = new string (Enumerable.Repeat(chars, cvlength).Select(s => s[random.Next(s.Length)]).ToArray());
string codeChallenge;
using (var sha256 = SHA256.Create())
{
var a = Encoding.UTF8.GetBytes(codeVerifier);
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
codeChallenge = Base64Url.Encode(challengeBytes);
}
Console.WriteLine("codeVerifier " + codeVerifier + "\n");
Console.WriteLine("codeChallenge " + codeChallenge + "\n");
Console.ReadLine();
}
}
}
Ответ:
Теперь я запустил ниже запрос авторизации в браузере и успешно получил такой код:
https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-3526417d4d09
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=openid
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256
Ответ:
Когда я попытался сгенерировать токены через Postman с указанными ниже параметрами, я получил только id_token
и refresh_token
без токена доступа, как показано ниже:
POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token
client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope:openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N
Ответ:
Чтобы получить токен доступа, добавьте новую область действия, предоставив API, как показано ниже:
Теперь добавьте этот scope
в свое приложение, которое будет иметь делегированные разрешения, как показано ниже:
Обязательно дайте согласие администратора на указанную выше область, как показано ниже:
Теперь снова сгенерируйте code
, выполнив приведенный ниже запрос авторизации в браузере следующим образом.
https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-xxxxxxxxxx
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxx/.default
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256
Ответ:
Я успешно сгенерировал токен доступа, используя следующие параметры через Postman, как показано ниже:
POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token
client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope: https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxxx/Admin.Read openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N
Ответ:
Когда я расшифровал вышеуказанный токен доступа в jwt.ms, я получил утверждение scp
, как показано ниже:
Спасибо! Похоже, проблема была в отправке client_secret в запросе, когда я удалил этот параметр, как в вашем примере, тогда он сработал.
Вы видели и пробовали это stackoverflow.com/questions/71139597/…?