Přihlašování přes Microsoft Azure (Entra ID, oauth2, OIDC) (Návod)

- ludek2
- Člen | 1
Píšeme aplikaci pro firmu, kde mají povinné dvoufaktorové (2FA, MFA) ověřování proti Microsoftímu serveru.
Vyřešíme v Nette s pomocí contributte/oauth2-client.
0. Registrace naší aplikace na portal.azure.com, resp. entra.microsoft.com
- Důležité je správně nastavit
Redirect URI, čili kam Microsoft po přihlášení uživatele vrátí (např.http://localhost/projekt/www/sign/azure-callback) - Dále získat:
Application (client) ID,Client Secret/Value,Directory (tenant) ID - V sekci Authentication u vaší aplikace nezapomeňte povolit
ID tokensa v API permissions přidat delegované oprávněníUser.Read.
(Přejeme pevné nervy.)
1. Instalace balíčků
oauth2-client neumí Azure, takže musíme přiinstalovat ještě
Third-party
Provider Client oauth2-azure.
composer require contributte/oauth2-client
composer require thenetworg/oauth2-azure
2. Flow
Protože základní Flow v balíčku contributte/oauth2-client je
abstraktní, vytvoříme jednoduchou implementaci v pomocné třítě
app/Model/AzureFlow.php, kde mu jen pomůžeme
získat správný Provider (tedy Azure). Tuto třídu potom zaregistrujeme jako
službu v configu a předáme si ji jako závislost do přihlašovacího
presenteru, kde nám vygeneruje externí odkaz a zpracuje odpověď
autorizačního serveru:
<?php
declare(strict_types=1);
namespace App\Model;
use Contributte\OAuth2Client\Flow\AuthCodeFlow;
use TheNetworg\OAuth2\Client\Provider\Azure;
/**
* Azure AD implementation of OAuth2 AuthCodeFlow
*/
class AzureFlow extends AuthCodeFlow {
/**
* @return Azure
*/
public function getProvider(): Azure {
return $this->provider;
}
}
3. Konfigurace
v local.neon nastavíme parametry, co jsme dostali při
registraci aplikace:
parameters:
azure:
clientId: 'vaše-client-id' # Application (client) ID
clientSecret: 'vaše-client-secret' # Client Secret/Value
tenant: 'vaše-tenant-id' # Directory (tenant) ID
redirectUri: 'http://localhost/projekt/www/sign/azure-callback'
4. Registrace služeb
v common.neon: zaregistrujeme Azure providera a Flow.
Důležité je vynutit verzi koncového bodu 2.0 a definovat scopes (tzn. co
nám bude vráceno zpět).
services:
azureProvider:
factory: TheNetworg\OAuth2\Client\Provider\Azure([
clientId: %azure.clientId%,
clientSecret: %azure.clientSecret%,
redirectUri: %azure.redirectUri%,
tenant: %azure.tenant%,
defaultEndPointVersion: '2.0',
scopes: ['openid', 'profile', 'email']
])
azureFlow: App\Model\AzureFlow(@azureProvider)
Podle toho se
- připraví provider: Nette vytvoří instanci Azure providera a naplní ho
vašimi údaji z
local.neon. - sestaví Flow: Nette vyrobí instanci AzureFlow a do jejího konstruktoru automaticky vloží připravený provider.
5. Implementace přihlašování
V SignPresenter vytvoříme akci pro přesměrování ven na
Azure a callback pro zpracování návratu. Abychom mohli volat AzureFlow,
musíme ho vložit jako závislost.
use App\Model\AzureFlow;
// Model\AzureFlow si předejte jak jste zvyklí
/** @var AzureFlow */
private $azureFlow;
public function __construct(AzureFlow $azureFlow)
{
$this->azureFlow = $azureFlow;
}
// Přesměruje na odkaz ve kterém jsou parametry, kterým Azure rozumí.
// Na tuto akci bude odkazovat přihlašovací tlačítko.
public function actionAzureLogin(): void {
$this->redirectUrl($this->azureFlow->getAuthorizationUrl());
}
// Bod návratu po přihlášení u Microsoftu
public function actionAzureCallback(): void {
try {
// 1. Získání tokenu
$token = $this->azureFlow->getAccessToken($this->getHttpRequest()->getQuery());
// 2. Získání dat o uživateli z MS
$azureUser = $this->azureFlow->getProvider()->getResourceOwner($token);
// Azure vrací e-mail v poli 'mail' nebo 'userPrincipalName'
$email = $azureUser->getUpn() ?: $azureUser->getEmail();
if (!$email) { throw new \Exception('Z Azure AD se nepodařilo získat e-mail uživatele.'); }
// 3. Hledáme uživatele u sebe podle obdrženého emailu
$identity = $this->database->table('users')->where('email', $email)->fetch();
if (!$identity) {
// Uživatel je v Azure v pořádku, ale nemá u nás založený účet
$this->flashMessage("Uživatel '$email' nemá v aplikaci povolen přístup. Kontaktujte administrátora.", 'danger');
$this->redirect('in');
}
// 4. Přihlášení do Nette
$this->getUser()->login($identity);
$this->flashMessage('Úspěšné přihlášení účtem Microsoft.', 'success');
// Přesměrování
$this->restoreRequest($this->backlink);
$this->redirect('Homepage:');
} catch (\Throwable $e) {
// Pokud jde o výjimku pro přesměrování, necháme projít, jinak se přesměrování neprovede
if ($e instanceof AbortException) { throw $e; }
$this->flashMessage('Chyba při přihlašování přes Azure: ' . $e->getMessage(), 'danger');
$this->redirect('in');
}
}
6. Šablona
do šablony Sign.in.latte dáme přihlašovací tlačítko
<a n:href="azureLogin" class="btn btn-outline-primary">
Přihlásit se přes Microsoft
</a>
Hotovo.
Editoval ludek2 (Dnes 19:48)