Zum Hauptinhalt springen

API Login

Die Authentifizierung mit JSON Web Token (JWT) wird mit Hilfe des Packages LexikJWTAuthenticationBundle durchgeführt.

Login

Der API-Login-Prozess im Detail:

  1. Der JSONLoginAuthenticator wird aufgerufen, der den username und das password aus dem Request extrahiert. Er validiert die Credentials mit Hilfe des UserProviders: ApiUserService. Im Erfolgsfall ruft er den ApiAuthenticationSuccessHandler auf, ansonsten den ApiAuthenticationFailureHandler.
  2. Den JWT-Token generieren. Falls 2FA aktiviert ist, wird lediglich ein partieller JWT-Token (type=partial) erstellt.
  3. Den Response mit dem JSON-Parameter "twofa" erweitern
  4. Ein AuthenticationFailureEvent erstellen und diesen Event dispatchen.
  5. Dieser Event wird im ApiAuthenticationListener in der Funktion onAuthenticationFailureResponse konsumiert. Hier wird ein JWTAuthenticationFailureResponse erstellt.
  6. Symfony sendet den Response (aus 3. oder 5.) an den Client

Dashboard

2FA

Falls 2FA aktiviert ist muss zusätzlich der 2FA-Token validiert werden.

  1. Symfony und LexikJWTAuthenticationBundle übernehmen die Kontrolle

  2. In ApiAuthenticationListener in der Funktion onJWTAuthenticated() 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
    }
  3. Die Route api1_v1_twofacheck ist im Controller Api2FAController definiert. Dieser ruft die Funktion checkTwofaApi() in der Klasse ContactService auf.

  4. Hier wird der 2FA-Token überprüft. Falls der Token nicht korrekt ist, wird eine APIException geworfen.

    {
    "code": 401,
    "type": "authorization_error",
    "message": "2FA authorization failed"
    }

    War die 2FA-Token-Validierung hingegen erfolgreich, wird im ApiAuthenticationSuccessHandler die Funktion onAuthentication2FASuccess() aufgerufen.

  5. Hier wird der finale JWT-Token erstellt (type=full)

  6. Noch einmal wird in ApiAuthenticationListener die Funktion onAuthenticationSuccessResponse() aufgerufen. In diesem Fall wird der Parameter twofa nicht hinzugefügt.

  7. Symfony sendet den Response an den Client

    {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI3MzI5NDQsI...rbaQnA",
    }

Dashboard

Konfigurationen

config\packages\security.yaml
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 }
config\services.yaml
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 }
config\packages\lexik_jwt_authentication.yaml
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)%'
.env
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