API Login
Die Authentifizierung mit JSON Web Token (JWT) wird mit Hilfe des Packages LexikJWTAuthenticationBundle durchgeführt.
Login
Der API-Login-Prozess im Detail:
- Der
JSONLoginAuthenticatorwird aufgerufen, der denusernameund daspasswordaus dem Request extrahiert. Er validiert die Credentials mit Hilfe des UserProviders:ApiUserService. Im Erfolgsfall ruft er denApiAuthenticationSuccessHandlerauf, ansonsten denApiAuthenticationFailureHandler. - Den JWT-Token generieren. Falls 2FA aktiviert ist, wird lediglich ein partieller JWT-Token (type=partial) erstellt.
- Den Response mit dem JSON-Parameter "twofa" erweitern
- Ein
AuthenticationFailureEventerstellen und diesen Event dispatchen. - Dieser Event wird im
ApiAuthenticationListenerin der FunktiononAuthenticationFailureResponsekonsumiert. Hier wird einJWTAuthenticationFailureResponseerstellt. - Symfony sendet den Response (aus 3. oder 5.) an den Client

2FA
Falls 2FA aktiviert ist muss zusätzlich der 2FA-Token validiert werden.
-
Symfony und LexikJWTAuthenticationBundle übernehmen die Kontrolle
-
In
ApiAuthenticationListenerin der FunktiononJWTAuthenticated()muss sichergestellt werden, dass ein partieller JWT-Token im Falle von api1_v1_twofacheck erlaubt ist// Für 2FA check: Partial Token akzeptieren
if ($routeName == 'api_v1_twofacheck' && $payload['type'] === 'partial') {
return; // Erlaubt
} -
Die Route api1_v1_twofacheck ist im Controller
Api2FAControllerdefiniert. Dieser ruft die FunktioncheckTwofaApi()in der KlasseContactServiceauf. -
Hier wird der 2FA-Token überprüft. Falls der Token nicht korrekt ist, wird eine
APIExceptiongeworfen.{
"code": 401,
"type": "authorization_error",
"message": "2FA authorization failed"
}War die 2FA-Token-Validierung hingegen erfolgreich, wird im
ApiAuthenticationSuccessHandlerdie FunktiononAuthentication2FASuccess()aufgerufen. -
Hier wird der finale JWT-Token erstellt (type=full)
-
Noch einmal wird in
ApiAuthenticationListenerdie FunktiononAuthenticationSuccessResponse()aufgerufen. In diesem Fall wird der Parameter twofa nicht hinzugefügt. -
Symfony sendet den Response an den Client
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI3MzI5NDQsI...rbaQnA",
}

Konfigurationen
security:
password_hashers:
App\Model\User:
algorithm: bcrypt
App\Model\Contact:
algorithm: bcrypt
providers:
clubhouse23_apiuser_provider:
id: App\Service\ApiUserService
firewalls:
apilogin:
pattern: ^/api/login
stateless: true
provider: clubhouse23_apiuser_provider
json_login:
check_path: api_login
success_handler: app.handler.apiauthentication_success
failure_handler: app.handler.apiauthentication_failure
access_control:
- { path: '^/api/login', roles: PUBLIC_ACCESS }
services:
# JWT Handler
app.handler.apiauthentication_success:
class: App\Security\ApiAuthenticationSuccessHandler
app.handler.apiauthentication_failure:
class: App\Security\ApiAuthenticationFailureHandler
# JWT Event Listeners
app.event.jwt_authenticated_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_authenticated, method: onJWTAuthenticated }
app.event.authentication_success_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccessResponse }
app.event.authentication_failure_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_failure, method: onAuthenticationFailureResponse }
app.event.jwt_invalid_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_invalid, method: onJWTInvalid }
app.event.jwt_notfound_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_not_found, method: onJWTNotFound }
app.event.jwt_expired_listener:
class: App\EventProcessing\ApiAuthenticationListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_expired, method: onJWTExpired }
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: '%env(JWT_TOKEN_TTL)%'
lexik_jwt_authentication:
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=2b5a2426974c0ad9448e53051ede61a3
JWT_TOKEN_TTL=3600