Guida al "Sign In with Apple"  pt.2

Backend

Netfarm

Questa è la seconda parte della guida, nel post precedente Guida al "Sign In" con Apple pt.1  abbiamo visto come procurarci le chiavi necessarie per procedere all'implementazione. In questa guida illustreremo la parte del Backend in Django e la parte Mobile in Flutter

Il Backend (Django)

django backend tutorial netfarm
L'esempio di backend che descriverò è in Django. (Web Framework di Python) 

Requisiti 

Per implementare il Login di Apple su un Backend basato su Django, avremo bisogno di un Server con un progetto di Django 2.0 o superiore, con PythonSocial OAuth e tutte le chiavi ottenute da Apple nella guida precedente. 


Riassunto delle chiavi necessarie

Key ID (l'ID della chiave generata all'interno del Apple's Developer Portal)

Apple Developer Team ID 

Client ID (iOS App Bundle ID, it.example.app)

Client Secret

Come Funziona? Un veloce riassunto

Apple ha adottato gli standard esistenti 0Auth 2.0 e Open ID Connect da utilizzare come base per la loro nuova API

accedi con apple come funziona
Vediamo quindi come creare una applicazione in grado di sfruttare la nuova API di Apple per far accedere gli utenti.

1) Prepara i Setting

Per prima cosa vanno configurati i settings.py aggiungendo queste righe di codice e inserendo le chiavi ottenute precedentemente.


SOCIAL_AUTH_APPLE_ID_CLIENT = '...' # Your client_id com.application.your, aka "Service ID"
SOCIAL_AUTH_APPLE_ID_TEAM = '...' # Your Team ID, ie K2232113
SOCIAL_AUTH_APPLE_ID_KEY = '...' # Your Key ID, ie Y2P99J3N81K
SOCIAL_AUTH_APPLE_ID_SECRET = """
-----BEGIN PRIVATE KEY-----
MIGTAgE.....
-----END PRIVATE KEY-----"""
SOCIAL_AUTH_APPLE_ID_SCOPE = ['email', 'name']
SOCIAL_AUTH_APPLE_ID_EMAIL_AS_USERNAME = True # If you want to use email as username
```


E all'interno dei backend di autenticazione

 
SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
...
'social_core.backends.apple.AppleIdAuth',
...
)
 

2) Gestione dispositivi Android (opzionale)

Per permettere anche ai dispositivi Android di usufruire del Login con Apple, sarà necessario esporre una chiamata speciale da parte del server che autorizzi il device ad accedere ai contenuti Apple.

 
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt


@csrf_exempt
def apple_redirect(request):
post_data = request.POST
print(post_data)
query_params = ''
for key,value in request.POST.items():
query_params += f'{key}={value}&'

query_params = query_params[:-1]
print(query_params)
response = HttpResponse("", status=302)
response['Location'] = f'intent://callback?{query_params}#Intent;package={settings.PACKAGE_APP}; scheme=signinwithapple;end'
return response
 

Una volta creata la chiamata va inserita negli urls.py dell'app che la contiene:

 
from django.conf.urls import url, include
from auth_manager import views

urlauthrest = [
....,
url(r'^oauth/', include('rest_framework_social_oauth2.urls')),
url(r'^oauth/apple/', views.apple_redirect),
....
]

Anche se alla prima occhiata può sembrare complicata, l'unica cosa di cui avremo bisogno adesso sono

1.  I token generati dall'App al momento del tentativo di Login con Apple 
2. Inserirli nel campo 'Location' con lo specifico intent url.

Questa chiamata darà modo al device Android di accedere a i dati sensibili Apple e ad accedere con un autenticazione.

Consigliamo tuttavia di implementare l'autentificazione con Apple solo per la parte iOS, questo perchè Android per autenticarsi lancia una webview che richiedere un'autenticazione a due fattori per cui sarà comunque necessario avere un dispositivo Apple con se.

Per sapere se l'applicazione sta girando su iOSFlutter fornisce un boolean Platforms.isIOS così da disabilitare o nascondere il tasto sulle altre piattaforme. Se in ogni caso si prevede di implementare questo meccanismo anche su Android, è il caso di aggiungere al manifest la seguente activity.


<activity
android:name="com.aboutyou.dart_packages.sign_in_with_apple.SignInWithAppleCallback"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="signinwithapple" />
<data android:path="callback" />
</intent-filter>
</activity>

Non stai usando Python Social Auth?

Se non stai utilizzando Python Social Auth, puoi creare manualmente l'utente dopo la convalida e la decodifica dell'id_token che hai ricevuto da Apple.

1. Nel caso in cui l'ID esista già, si tratta dello stesso utente, devi solo accedere.Nel nostro caso Python Social Auth lo sta già facendo)

INTEGRAZIONE IN APP

come accedere con apple netfarm
Il backend è pronto a ricevere migliaia di richieste adesso si passa alle App! 

L'ultima parte del nostro lavoro quindi consisterà del vedere come integrare sulle mobile app sviluppate in Flutter questa metodologia di Login.

Requisiti

Il primo passo richiede di aggiungere tra le dipendenze del proprio progetto l'ultima versione di:

sign_in_with_apple](https://pub.dev/packages/sign_in_with_apple)

Per farlo basta aggiungere nelle dependencies all'interno del file yaml del progetto la riga

dependencies: sign_in_with_apple: <last_version>

Integrazione

Una volta introdotta la dipendenza è possibile iniziare l'integrazione effettuando questi pochi e semplici passaggi.

1. Creare il pulsante all'interno del layout

button sign in apple netfarm











Creare il pulsante da premere per effettuare il Login e creare la propria funzione da chiamare quando viene scatenato l'evento onPressed. Da notare che la libreria importata fornisce già un tasto che propone lo stile ufficiale proposto da Apple, ma che può anche essere fortemente customizzata

 
SignInWithAppleButton(
onPressed: clickAppleButton )

2. Definire la funzione
Definire la funzione che gestirà il click del pulsante

Future<void> clickAppleButton() async { try { //consiglio di effettuare l'update della vista di login notificandolo con una setState il login in corso final credential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], webAuthenticationOptions: WebAuthenticationOptions( clientId: '<client_id>', redirectUri: Uri.parse( '<url_backend_login_apple>', ), ), ); await doAppleLogin(credential.identityToken, credential.userIdentifier); }catch(err){ //effettuare l'update del layout, notificare l'errore } }


La funzione chiama il metodo SignInWithApple.getAppleIDCredential, questa richiamerà la vista per la richiesta dell'autenticazione con Apple, sarà Flutter a specializzare poi la vista.

I campi standard che la funzione tornerà sono
- userIdentifier (id dell'utente) 
- identityToken (il Token dell'utente) 
Lo scope contiene la lista dei campi che stiamo chiedendo di fornire extra. Per il corretto funzionamento è importante inserire
- Il corretto clientId definito nel momento della creazione della chiave nella prima parte di questa guida-
-  redirectUri ovvero la pagina del backend che si occupa del login (definita invece nella seconda parte).

Se tutto è andato bene basterà lo userIdentifier e l'identityToken alla chiamata di Login del backend associato che si occuperà di completare l'autenticazione restituendoci un token generico che permetterà all'app di proseguire autonomamente.

Conclusioni

L'autenticazione con Apple su Flutter, come avrete potuto capire, richiede pochi passaggi, le difficoltà che si potrebbero incontrare sono legate ai primi tentativi di comunicazioni tra backend e app. In quel caso è bene controllare che le chiavi generate e imposte siano giuste. 

Una volta funzionante su iOS risulta molto comodo e pratico il login così implementato. Non si può dire la stessa cosa su Android, il dover dipendere dall'autenticazione a due fattori, che richiede di avere un secondo dispositivo con se, ne rende frustrante l'utilizzo.