Dopo aver configurato il servizio backend in Azure è possibile proseguire nella costruzione della app aggiungendo l'autenticazione. Il codice lo trovate in linkografia.

Iniziamo a vedere che nella classe delegata a chiaccherare con il backend Azureè stato aggiunto un metodo che server per eseguire il login.

public Task LoginAsync()
{

	var loginProvider = DependencyService.Get(<ILoginProvider>);
	return loginProvider.LoginAsync(client);
}

Siccome tutta la baracca dell'autenticazione server-flow si basa su webview occorre agire sul codice nativo (quindi sul progetto android nel ns caso). Per fare questo occorre usare la funzionalità DependencyService di Xamarin. Richiamando quindi LoginAsync nella classe AzureMobileClient si chiamerà in realtà il DroidLoginProvider dentro il progetto Android.

[assembly: Xamarin.Forms.Dependency(typeof(DroidLoginProvider))]
namespace AppFocGenova
{
    public class DroidLoginProvider : ILoginProvider
    {
        Context context;
        public void Init(Context context)
        {
            this.context = context;
        }

        public async Task LoginAsync(MobileServiceClient client)
        {
            var res = await client.LoginAsync(context, MobileServiceAuthenticationProvider.Facebook, "apnm");
            
        }
    }

Quanto sopra esegue l'autenticazione server-flow presso il backend Azure, e che usa a sua volta come IdP Facebook: in caso di successo l'oggetto client (di tipo MobileServiceClient) sarà popolato con il token finale.

Rammento che questo token finale è quello rilasciato dai servizi Azure.

E' possibile accedere a questo token, nonchè ai dati relativi all'autenticazione, usando la proprietà CurrentUser dell'oggetto stesso.

Per esempio client.CurrentUser.MobileServiceAuthenticationToken restituisce il token rilasciato dai servizi Azure.

Se l'autenticazione non è avvenuta questa proprietà restituirà, in modo sensato, un bel NULL.

Per permettere l'accesso ai controller del backend ai soli device autorizzato occorre mettere mano al codice del backend stesso.

[Authorize]
public class FocaccePostController : TableController
{
	protected override void Initialize(HttpControllerContext controllerContext)
	{
		base.Initialize(controllerContext);
		Focac_BookContext context = new Focac_BookContext();
		DomainManager = new EntityDomainManager(context, Request,true);
	}

	// GET tables/TodoItem
	public IQueryable GetAllFocaccePost()
	{

		return Query();
	}

	// GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
	public SingleResult GetFocaccePost(string id)
	{
		return Lookup(id);
	}

	// PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
	public Task PatchFocaccePost(string id, Delta<FocaccePost>  patch)
	{
		return UpdateAsync(id, patch);
	}

	// POST tables/TodoItem
	public async Task<IHttpActionResult> PostFocaccePost(FocaccePost item)
	{
		FocaccePost current = await InsertAsync(item);
		return CreatedAtRoute("Tables", new { id = current.Id }, current);
	}

	// DELETE tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
	public Task DeleteFocaccePost(string id)
	{
		return DeleteAsync(id);
	}
}

 

L’attributo Authorization serve per specificare che una risorsa può essere usata solo da un utente autenticato

Oss.: E’ anche possibile porre lo stesso attributo solo su alcune operazioni: per esempio permettere a tutti di leggere il contenuto (GetAllFocaccePost) ma permettere solo agli utenti autenticati di eseguire operazioni CUD: in tal caso l’attributo sarebbe stato posto solo nei relativi metodi.

Per poter dimostrare al backend che si è correttamente completato il processo di autenticazione occorre aggiungere ad ogni richiesta il token rilasciato nella fase di login. Solo per chiamate così corredate è possibile accedere ai metodi del controller adornati con [Authorize].

Più nello specifico questo token deve essere aggiunto nell'header di ogni chiamata verso i servizi del backend Azure.

Scorrendo il codice che ho proposto si vedrà che questa "aggiuntina" non avviene in nessun punto: infatti usando l'oggetto client con la proprietà CurrentUser corretamente popolata in fase di login tutte le chiamate verso il backend saranno dotate del token corretto senza dover fare alcunchè in modo esplicito.

Per tale motivo se per esempio a un certo punto di ponesse l'oggetto client a NULL, e quindi si reinstanziasse successivamente senza però alcuna operazione di login, la proprietà CurrentUser sarebbe NULL, ed eventauli utilizzi di questo oggetto verso il backend (per esempio una chiamata PullAsync) fallirebbero miseramente poichè nell'header non sarebbe aggiunto alcun token di autenticazione e la chiamata non raggiungerebbe il controller (l'infrastruttura Azure fermerebbe la chiamata molto prima).

Per lo stesso motivo nel codice della app presentata affinchè tutto funzioni correttamente occorre eseguire un login ad ogni riavvio della app (anche se non vengono richieste le credenziali dall'IdP perchè già salvate nella cache del browser in ogni caso ad ogni avvio si esegue l'intero processo di login al fine di popolare la proprietà CurrentUser dell'oggetto client).

Utilizzi più professionali dell'SDK dovrebbero prevedere una persistenza del token rilasciato nonchè una corretta creazione dell'oggetto client gestendo il token ottenuto da precedenti login.

La complicazione per implementare un processo di questo genere è introdurre una persistenza "sicura" nonchè anche gestire la scadenza: infatti per complicare il tutto il token ottenuto ha una scadenza ben stabilita, passata la quale occorre mettere in campo delle azioni di refresh dello stesso o anche un nuovo login presso i servizi.

Linkografia

Git Page: Focac-Book in Xamarin