Uso di provider OAuth con MVC 4

di Tom FitzMacken

Questa esercitazione illustra come creare un'applicazione Web ASP.NET MVC 4 che consente agli utenti di accedere con credenziali da un provider esterno, ad esempio Facebook, Twitter, Microsoft o Google, e quindi integrare alcune delle funzionalità di tali provider nell'applicazione Web. Per semplicità, questa esercitazione si concentra sull'uso delle credenziali da Facebook.

Per usare le credenziali esterne in un'applicazione Web MVC 5 ASP.NET, vedere Creare un'app MVC 5 ASP.NET con Facebook e Google OAuth2 e OpenID Sign-On.

L'abilitazione di queste credenziali nei siti Web offre un vantaggio significativo perché milioni di utenti hanno già account con questi provider esterni. Questi utenti potrebbero essere più propensi ad iscriversi per il sito se non devono creare e ricordare un nuovo set di credenziali. Inoltre, dopo che un utente ha eseguito l'accesso tramite uno di questi provider, è possibile incorporare operazioni social dal provider.

Obiettivo

In questa esercitazione sono disponibili due obiettivi principali:

  1. Abilitare un utente per accedere con le credenziali da un provider OAuth.
  2. Recuperare le informazioni sull'account dal provider e integrare tali informazioni con la registrazione dell'account per il sito.

Anche se gli esempi di questa esercitazione si concentrano sull'uso di Facebook come provider di autenticazione, è possibile modificare il codice per usare uno qualsiasi dei provider. I passaggi per implementare qualsiasi provider sono molto simili ai passaggi visualizzati in questa esercitazione. Si noteranno solo differenze significative quando si effettuano chiamate dirette al set di API del provider.

Prerequisiti

Oppure

Inoltre, questo argomento presuppone che si disponga di conoscenze di base su ASP.NET MVC e Visual Studio. Se è necessaria un'introduzione a ASP.NET MVC 4, vedere Introduzione a ASP.NET MVC 4.

Creare il progetto

In Visual Studio creare una nuova applicazione Web MVC 4 ASP.NET e denominarla "OAuthMVC". È possibile usare .NET Framework 4.5 o 4.

creare un progetto

Nella finestra Nuovo ASP.NET progetto MVC 4 selezionare Applicazione Internet e lasciare Razor come motore di visualizzazione.

Selezionare Applicazione Internet

Abilitare un provider

Quando si crea un'applicazione Web MVC 4 con il modello applicazione Internet, il progetto viene creato con un file denominato AuthConfig.cs nella cartella App_Start.

File AuthConfig

Il file AuthConfig contiene codice per registrare i client per i provider di autenticazione esterni. Per impostazione predefinita, questo codice viene commentato, quindi nessuno dei provider esterni è abilitato.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        // To let users of this site log in using their accounts from other sites such as Microsoft, Facebook, and Twitter,
        // you must update this site. For more information visit https://go.microsoft.com/fwlink/?LinkID=252166

        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        //OAuthWebSecurity.RegisterFacebookClient(
        //    appId: "",
        //    appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();
    }
}

È necessario annullare ilcommentazione di questo codice per usare il client di autenticazione esterna. Si annulla ilcommento solo i provider che si desidera includere nel sito. Per questa esercitazione si abiliteranno solo le credenziali di Facebook.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        OAuthWebSecurity.RegisterFacebookClient(
            appId: "",
            appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();        
    }
}

Si noti nell'esempio precedente che il metodo include stringhe vuote per i parametri di registrazione. Se si tenta di eseguire l'applicazione ora, l'applicazione genera un'eccezione di argomento perché le stringhe vuote non sono consentite per i parametri. Per fornire valori validi, è necessario registrare il sito Web con i provider esterni, come illustrato nella sezione successiva.

Registrazione con un provider esterno

Per autenticare gli utenti con credenziali da un provider esterno, è necessario registrare il sito Web con il provider. Quando si registra il sito, si riceveranno i parametri (ad esempio chiave o ID e segreto) da includere durante la registrazione del client. È necessario disporre di un account con i provider che si desidera usare.

Questa esercitazione non mostra tutti i passaggi da eseguire per registrare con questi provider. I passaggi in genere non sono difficili. Per registrare correttamente il sito, seguire le istruzioni fornite in tali siti. Per iniziare a registrare il sito, vedere il sito per sviluppatori per:

Quando si registra il sito con Facebook, è possibile fornire "localhost" per il dominio del sito e "http://localhost/" per l'URL, come illustrato nell'immagine seguente. L'uso di localhost funziona con la maggior parte dei provider, ma attualmente non funziona con il provider Microsoft. Per il provider Microsoft, è necessario includere un URL del sito Web valido.

registrare il sito

Nell'immagine precedente sono stati rimossi i valori per l'ID app, il segreto dell'app e il messaggio di posta elettronica di contatto. Quando si registra effettivamente il sito, questi valori saranno presenti. Si desidera prendere nota dei valori per l'ID app e il segreto dell'app perché verranno aggiunti all'applicazione.

Creazione di utenti di test

Se non si vuole usare un account Facebook esistente per testare il sito, è possibile ignorare questa sezione.

È possibile creare facilmente utenti di test per l'applicazione all'interno della pagina di gestione delle app Facebook. È possibile usare questi account di test per accedere al sito. Si creano utenti di test facendo clic sul collegamento Ruoli nel riquadro di spostamento a sinistra e facendo clic sul collegamento Crea .

creare utenti di test

Il sito Facebook crea automaticamente il numero di account di test richiesti.

Aggiunta dell'ID applicazione e del segreto dal provider

Dopo aver ricevuto l'ID e il segreto da Facebook, tornare al file AuthConfig e aggiungerli come valori dei parametri. I valori illustrati di seguito non sono valori reali.

public static class AuthConfig
{
    public static void RegisterAuth()
    {
        //OAuthWebSecurity.RegisterMicrosoftClient(
        //    clientId: "",
        //    clientSecret: "");

        //OAuthWebSecurity.RegisterTwitterClient(
        //    consumerKey: "",
        //    consumerSecret: "");

        //OAuthWebSecurity.RegisterFacebookClient(
        //    appId: "",
        //    appSecret: "");

        //OAuthWebSecurity.RegisterGoogleClient();
    }
}

Accedere con credenziali esterne

È tutto ciò che devi fare per abilitare le credenziali esterne nel tuo sito. Eseguire l'applicazione e fare clic sul collegamento di accesso nell'angolo superiore destro. Il modello riconosce automaticamente che facebook è stato registrato come provider e include un pulsante per il provider. Se si registrano più provider, viene incluso automaticamente un pulsante per ognuno di essi.

accesso esterno

Questa esercitazione non illustra come personalizzare i pulsanti di accesso per i provider esterni. Per queste informazioni, vedere Personalizzazione dell'interfaccia utente di accesso quando si usa OAuth/OpenID.

Fare clic sul pulsante Facebook per accedere con le credenziali di Facebook. Quando si seleziona uno dei provider esterni, si viene reindirizzati a tale sito e viene richiesto da tale servizio di accedere.

L'immagine seguente mostra la schermata di accesso per Facebook. Si nota che si usa l'account Facebook per accedere a un sito denominato oauthmvcexample.

autenticazione facebook

Dopo l'accesso con le credenziali di Facebook, una pagina informa l'utente che il sito avrà accesso alle informazioni di base.

autorizzazione richiesta

Dopo aver selezionato Vai all'app, l'utente deve registrarsi per il sito. L'immagine seguente mostra la pagina di registrazione dopo che un utente ha eseguito l'accesso con le credenziali di Facebook. Il nome utente viene in genere precompilato con un nome dal provider.

Screenshot che mostra una pagina Di registrazione in cui è possibile associare l'account Facebook a questa app.

Fare clic su Registra per completare la registrazione. Chiudere il browser.

È possibile notare che il nuovo account è stato aggiunto al database. In Esplora server aprire il database DefaultConnection e aprire la cartella Tabelle .

tabelle di database

Fare clic con il pulsante destro del mouse sulla tabella UserProfile e scegliere Mostra dati tabella.

visualizzare i dati

Verrà visualizzato il nuovo account aggiunto. Esaminare i dati nella tabella webpage_OAuthMembership . Verranno visualizzati altri dati correlati al provider esterno per l'account appena aggiunto.

Se si vuole abilitare solo l'autenticazione esterna, è necessario eseguire questa operazione. Tuttavia, è possibile integrare ulteriormente le informazioni dal provider nel nuovo processo di registrazione utente, come illustrato nelle sezioni seguenti.

Creare modelli per informazioni utente aggiuntive

Come si è notato nelle sezioni precedenti, non è necessario recuperare informazioni aggiuntive per il funzionamento della registrazione dell'account predefinita. Tuttavia, la maggior parte dei provider esterni passa informazioni aggiuntive sull'utente. Le sezioni seguenti illustrano come conservare tali informazioni e salvarle in un database. In particolare, manterrà i valori per il nome completo dell'utente, l'URI della pagina Web personale dell'utente e un valore che indica se Facebook ha verificato l'account.

Si userà Migrazioni Code First per aggiungere una tabella per archiviare informazioni aggiuntive sull'utente. Si aggiunge la tabella a un database esistente, quindi è prima necessario creare uno snapshot del database corrente. Creando uno snapshot del database corrente, è possibile creare successivamente una migrazione contenente solo la nuova tabella. Per creare uno snapshot del database corrente:

  1. Aprire la console di Gestione pacchetti
  2. Eseguire il comando enable-migrations
  3. Eseguire il comando add-migration initial –IgnoreChanges
  4. Eseguire il comando update-database

Ora si aggiungeranno le nuove proprietà. Nella cartella Models aprire il file AccountModels.cs e trovare la classe RegisterExternalLoginModel. La classe RegisterExternalLoginModel contiene valori restituiti dal provider di autenticazione. Aggiungere proprietà denominate FullName e Link, come evidenziato di seguito.

public class RegisterExternalLoginModel
{
    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }

    public string ExternalLoginData { get; set; }

    [Display(Name = "Full name")]
    public string FullName { get; set; }

    [Display(Name = "Personal page link")]
    public string Link { get; set; }
}

In AccountModels.cs aggiungere anche una nuova classe denominata ExtraUserInformation. Questa classe rappresenta la nuova tabella che verrà creata nel database.

[Table("ExtraUserInformation")]
public class ExternalUserInformation
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string FullName { get; set; }
    public string Link { get; set; }
    public bool? Verified { get; set; }
}

Nella classe UsersContext aggiungere il codice evidenziato seguente per creare una proprietà DbSet per la nuova classe.

public class UsersContext : DbContext
{
    public UsersContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<ExternalUserInformation> ExternalUsers { get; set; }
}

A questo momento è possibile creare la nuova tabella. Aprire di nuovo la console di Gestione pacchetti e questa volta:

  1. Eseguire il comando add-migration AddExtraUserInformation
  2. Eseguire il comando update-database

La nuova tabella è ora presente nel database.

Recuperare i dati aggiuntivi

Esistono due modi per recuperare dati utente aggiuntivi. Il primo modo consiste nel conservare i dati utente passati di nuovo, per impostazione predefinita, durante la richiesta di autenticazione. Il secondo modo consiste nel chiamare in modo specifico l'API del provider e richiedere altre informazioni. I valori per FullName e Link vengono passati automaticamente da Facebook. Valore che indica se Facebook ha verificato che l'account viene recuperato tramite una chiamata all'API Facebook. Prima di tutto, si popolano i valori per FullName e Link e successivamente si otterrà il valore verificato.

Per recuperare i dati utente aggiuntivi, aprire il file AccountController.cs nella cartella Controllers .

Questo file contiene la logica per la registrazione, la registrazione e la gestione degli account. In particolare, si notino i metodi denominati ExternalLoginCallback e ExternalLoginConfirmation. All'interno di questi metodi, è possibile aggiungere codice per personalizzare le operazioni di accesso esterne per l'applicazione. La prima riga del metodo ExternalLoginCallback contiene:

AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
    Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));

I dati utente aggiuntivi vengono passati nuovamente nella proprietà ExtraData dell'oggetto AuthenticationResult restituito dal metodo VerifyAuthentication . Il client Facebook contiene i valori seguenti nella proprietà ExtraData :

  • id
  • name
  • link
  • gender
  • accesstoken

Altri provider avranno dati simili ma leggermente diversi nella proprietà ExtraData.

Se l'utente non ha esperienza con il sito, si recupereranno alcuni dati aggiuntivi e si passeranno tali dati alla visualizzazione di conferma. L'ultimo blocco di codice nel metodo viene eseguito solo se l'utente non è nuovo nel sito. Sostituire la riga seguente:

return View("ExternalLoginConfirmation", new RegisterExternalLoginModel 
{ 
    UserName = result.UserName, 
    ExternalLoginData = loginData 
});

Con la riga seguente:

return View("ExternalLoginConfirmation", new RegisterExternalLoginModel
{
    UserName = result.UserName,
    ExternalLoginData = loginData,
    FullName = result.ExtraData["name"],
    Link = result.ExtraData["link"]
});

Questa modifica include semplicemente i valori per le proprietà FullName e Link.

Nel metodo ExternalLoginConfirmation modificare il codice come evidenziato di seguito per salvare le informazioni aggiuntive sull'utente.

if (user == null)
{
    // Insert name into the profile table
    UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
    db.SaveChanges();

    db.ExternalUsers.Add(new ExternalUserInformation 
    { 
        UserId = newUser.UserId, 
        FullName = model.FullName, 
        Link = model.Link 
    });
    db.SaveChanges();

    OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
    OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

    return RedirectToLocal(returnUrl);
}
else
{
    ModelState.AddModelError("UserName", "User name already exists. Please enter a different user name.");
}

Regolazione della visualizzazione

I dati utente aggiuntivi recuperati dal provider verranno visualizzati nella pagina di registrazione.

Nella cartella Views/Account aprire ExternalLoginConfirmation.cshtml. Sotto il campo esistente per nome utente, aggiungere campi per FullName, Link e PictureLink.

<li>
    @Html.LabelFor(m => m.FullName)
    @Html.TextBoxFor(m => m.FullName)
</li>
<li>
    @Html.LabelFor(m => m.Link)
    @Html.TextBoxFor(m => m.Link)
</li>

A questo punto si è quasi pronti per eseguire l'applicazione e registrare un nuovo utente con le informazioni aggiuntive salvate. È necessario disporre di un account che non è già registrato nel sito. È possibile usare un account di test diverso oppure eliminare le righe in UserProfile e webpages_OAuthMembership tabelle per l'account da riutilizzare. Eliminando queste righe, si garantisce che l'account venga registrato di nuovo.

Eseguire l'applicazione e registrare il nuovo utente. Si noti che questa volta la pagina di conferma contiene più valori.

Screenshot che mostra dove è possibile immettere un nome utente e altre informazioni dopo aver associato un account Facebook all'app.

Dopo aver completato la registrazione, chiudere il browser. Cercare nel database per notare i nuovi valori nella tabella ExtraUserInformation .

Installare il pacchetto NuGet per l'API Facebook

Facebook fornisce un'API che è possibile chiamare per eseguire operazioni. È possibile chiamare l'API Facebook indirizzando l'invio di richieste HTTP o installando un pacchetto NuGet che facilita l'invio di tali richieste. L'uso di un pacchetto NuGet è illustrato in questa esercitazione, ma l'installazione del pacchetto NuGet non è essenziale. Questa esercitazione illustra come usare il pacchetto SDK C# di Facebook. Sono disponibili altri pacchetti NuGet che consentono di chiamare l'API Facebook.

Nelle finestre Gestisci pacchetti NuGet selezionare il pacchetto FACEBOOK C# SDK.

installare il pacchetto

Si userà Facebook C# SDK per chiamare un'operazione che richiede il token di accesso per l'utente. La sezione successiva illustra come ottenere il token di accesso.

Recuperare il token di accesso

La maggior parte dei provider esterni passa un token di accesso dopo la verifica delle credenziali dell'utente. Questo token di accesso è molto importante perché consente di chiamare le operazioni disponibili solo per gli utenti autenticati. Pertanto, il recupero e l'archiviazione del token di accesso sono essenziali quando si desidera fornire più funzionalità.

A seconda del provider esterno, il token di accesso può essere valido solo per un periodo di tempo limitato. Per assicurarsi di disporre di un token di accesso valido, sarà possibile recuperarlo ogni volta che l'utente accede e archiviarlo come valore di sessione anziché salvarlo in un database.

Nel metodo ExternalLoginCallback il token di accesso viene passato anche nella proprietà ExtraData dell'oggetto AuthenticationResult . Aggiungere il codice evidenziato a ExternalLoginCallback per salvare il token di accesso nell'oggetto Session . Questo codice viene eseguito ogni volta che l'utente accede con un account Facebook.

[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
{
    AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(
        Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
    if (!result.IsSuccessful)
    {
        return RedirectToAction("ExternalLoginFailure");
    }

    if (result.ExtraData.Keys.Contains("accesstoken"))
    {
        Session["facebooktoken"] = result.ExtraData["accesstoken"];
    }

    if (OAuthWebSecurity.Login(
        result.Provider, 
        result.ProviderUserId, 
        createPersistentCookie: false))
    {
        return RedirectToLocal(returnUrl);
    }

    if (User.Identity.IsAuthenticated)
    {
        // If the current user is logged in add the new account
        OAuthWebSecurity.CreateOrUpdateAccount(
            result.Provider,
            result.ProviderUserId, 
            User.Identity.Name);
        return RedirectToLocal(returnUrl);
    }
    else
    {
        // User is new, ask for their desired membership name
        string loginData = OAuthWebSecurity.SerializeProviderUserId(
            result.Provider, 
            result.ProviderUserId);
        ViewBag.ProviderDisplayName =
            OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
        ViewBag.ReturnUrl = returnUrl;
        return View("ExternalLoginConfirmation", new RegisterExternalLoginModel
        {
            UserName = result.UserName,
            ExternalLoginData = loginData,
            FullName = result.ExtraData["name"],
            Link = result.ExtraData["link"]
        });    
    }
}

Anche se questo esempio recupera un token di accesso da Facebook, è possibile recuperare il token di accesso da qualsiasi provider esterno tramite la stessa chiave denominata "accesstoken".

Disconnessione

Il metodo LogOff predefinito registra l'utente dall'applicazione, ma non disconnette l'utente dal provider esterno. Per disconnettere l'utente da Facebook e impedire che il token venga salvato in modo permanente dopo la disconnessione dell'utente, è possibile aggiungere il codice evidenziato seguente al metodo LogOff in AccountController.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
    WebSecurity.Logout();
    if (Session["facebooktoken"] != null)
    {
        var fb = new Facebook.FacebookClient();
        string accessToken = Session["facebooktoken"] as string;
        var logoutUrl = fb.GetLogoutUrl(new { access_token = accessToken, next = "http://localhost:39852/" });

        Session.RemoveAll();
        return Redirect(logoutUrl.AbsoluteUri);
    }

    return RedirectToAction("Index", "Home");
}

Il valore specificato nel next parametro è l'URL da usare dopo che l'utente ha disconnesso da Facebook. Quando si esegue il test nel computer locale, si specifica il numero di porta corretto per il sito locale. Nell'ambiente di produzione è necessario specificare una pagina predefinita, ad esempio contoso.com.

Recuperare le informazioni utente che richiedono il token di accesso

Dopo aver archiviato il token di accesso e aver installato il pacchetto FACEBOOK C# SDK, è possibile usarli insieme per richiedere ulteriori informazioni utente da Facebook. Nel metodo ExternalLoginConfirmation creare un'istanza della classe FacebookClient passando il valore del token di accesso. Richiedere il valore della proprietà verificata per l'utente autenticato corrente. La proprietà verificata indica se Facebook ha convalidato l'account tramite altri mezzi, ad esempio l'invio di un messaggio a un telefono cellulare. Salvare questo valore nel database.

if (user == null)
{
    // Insert name into the profile table
    UserProfile newUser = db.UserProfiles.Add(new UserProfile { UserName = model.UserName });
    db.SaveChanges();

    bool facebookVerified;

    var client = new Facebook.FacebookClient(Session["facebooktoken"].ToString());
    dynamic response = client.Get("me", new { fields = "verified" });
    if (response.ContainsKey("verified"))
    {
        facebookVerified = response["verified"];
    }
    else
    {
        facebookVerified = false;
    }

    db.ExternalUsers.Add(new ExternalUserInformation 
    { 
        UserId = newUser.UserId, 
        FullName = model.FullName, 
        Link = model.Link, 
        Verified = facebookVerified 
    });
    db.SaveChanges();

    OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
    OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);

    return RedirectToLocal(returnUrl);
}

Sarà necessario eliminare nuovamente i record nel database per l'utente o usare un account Facebook diverso.

Eseguire l'applicazione e registrare il nuovo utente. Esaminare la tabella ExtraUserInformation per visualizzare il valore per la proprietà Verified.

Conclusione

In questa esercitazione è stato creato un sito integrato con Facebook per l'autenticazione utente e i dati di registrazione. Si è appreso il comportamento predefinito configurato per l'applicazione Web MVC 4 e come personalizzare il comportamento predefinito.