Autentizace pomoci Google OAuth 2.0

Jan Holan       28. 5. 2012       ASP.NET/IIS, Bezpečnost       7918 zobrazení

Google účet lze také podobně jako například u Windows Live nebo Facebook využít pro přihlašování do vlastního webu nebo aplikace. Google toto umožnuje buď pomoci OpenID (Google OpenID provider) nebo pomoci OAuth 2.0 protokolu (nástupce OAuth 1.0, které bylo pro přihlašování na Google již od 20.4.2012 označeno za deprecated). Zde je příklad na přihlášení do ASP.NET aplikace pomoci Google OAuth 2.0.

Registrace aplikace

Princip této Goole OAuth 2.0 autentizace je velice podobný jak jsme si uvedli u příkladu na přihlašování pomoci Facebooku nebo v příkladu na Window Live ID. Opět nejprve musíme provést vytvoření a nastavení vlastní aplikace, tentokrát pro vybraný Google účet. To se provádí ve službě Google apis tímto odkazem:

https://accounts.google.com/ServiceLogin?service=devconsole&passive=1209600&continue=https://code.google.com/apis/console/&followup=https://code.google.com/apis/console/

Po přihlášení se přepneme na záložku API Access a vytvoříme novou aplikaci (Create Client ID). Zvolíme Web application a nastavíme Your site or hostname a Redirect URI. Nelze zde ovšem zadat libovolná adresa, ale pouze buď doména nebo lze použít localhost pro testování, například tedy:

Redirect URIs: http://localhost/GoogleLoginSampleWeb/oauth2callback
JavaScript origins: http://localhost

nebo

Redirect URIs: http://mojedomena.com/GoogleLoginSampleWeb/oauth2callback
JavaScript origins: http://mojedomena.com

Po založení je vám vygenerováno Client ID a Client secret.

Rozchození příkladu

Kompletní ASP.NET web site příkladu je k dispozici ke stažení zde. Pro jeho rozběhnutí musíme doplnit naše Client IDClient secret do konstant v souboru Global.cs.

Ještě upozorním, že v příkladu není použita žádná externí knihovna, ačkoliv některé open source projekty existují (Google .NET Client API nebo přímo DotNetOpenAuth), přišlo mi, že konstrukci OAuth 2.0 requestů pro přihlášení je jednodušší provést přímo.

Volání OAuth 2.0 pro přihlášení webové aplikace

Projdeme si některý kód volání OAuth 2.0 pro přihlášení webové aplikace (Web Server flow) obsažený ve třídě GoogleAuthClient v příkladu. Jak již jsem psal, postup je velice podobný jako OAuth 2.0 přihlašení v případě Facebooku, takže hlavně upozorním na rozdíly.

1. Přihlašovací Url

Google OAuth 2.0 Login URL vypadá takto:

https://accounts.google.com/o/oauth2/auth?state=profile&response_type=code&redirect_uri=http%3a%2f%2flocalhost%2fGoogleLoginSampleWeb%2foauth2callback&client_id=000000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&approval_prompt=auto&scope=https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email

Podobně jako u Facebooku i zde pro webovou aplikaci volíme response_type typu code (volbu token by jsme opět využili spíše pro desktop aplikace). Dále ve volání již typicky uvádíme parametr redirect_uri a client_id naší aplikace.

Nový parametr je zde approval_prompt, ten může mít buď hodnotu auto nebo force. Zatímco při nastavení force je stránka pro potvrzení práv aplikace zobrazena vždy, při hodnotě auto se naopak stránka nezobrazuje v případě, že požadovanou aplikaci již uživatel jednou potvrdil. (Přístup k aplikaci může být uživatelem na této adrese ručně odstraněn).

Posledním parametrem je scope, ten určuje seznam požadovaných práv, ale na rozdíl od Facebook aplikací, zde máme pouze dvě hodnoty: profile – přístup k základním údajům profilu uživatele (ID, jméno, fotografie, URL, atd.) a email – přístup k email adrese uživatele (hodnoty se zadávají ve formě URL adresy).

Google Developers oficiální stránky popisující formát přihlašovacího URL zde. Kód na sestavení URL v příkladu najdete v metodě BuildLoginUrl.

2. Zpracování odpovědi

Po úspěšném přihlášení a autorizování aplikace (user consent) je volání vráceno na předané redirect_uri. V příkladu je URL GoogleLoginSampleWeb/oauth2callback, který je ve web.config nastaven na handler třídu OAuth2CallbackHandler. Odsud je zavolána metoda OnAuthenticateCompleted, ve které se vyzvedne code z odpovědi, která vypadá například takto:

http://localhost/GoogleLoginSampleWeb/oauth2callback?state=profile&code=0/xxx-xxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...

Dále je metodou GetAccessTokenForCode provedeno volání pro získání user access token. Kód vypadá takto:

private static GoogleOAuthResult GetAccessTokenForCode(string code, string clientID, string clientSecret, string redirectUri)
{
    string body = string.Format(cRequestAccessTokenPostBodyTemplate, code, HttpUtility.UrlEncode(clientID), HttpUtility.UrlEncode(clientSecret), HttpUtility.UrlEncode(redirectUri));

    var request = WebRequest.Create(cRequestAccessTokenUrl);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";

    try
    {
        using (var writer = new StreamWriter(request.GetRequestStream()))
        {
            writer.Write(body);
        }

        var response = request.GetResponse();
        if (response != null)
        {
            Stream responseStream = response.GetResponseStream();
            if (responseStream != null)
            {
                try
                {
                    var serializer = new DataContractJsonSerializer(typeof(RequestAccessTokenResponse));
                    var responseData = (RequestAccessTokenResponse)serializer.ReadObject(responseStream);
                    if (responseData != null)
                    {
                        return new GoogleOAuthResult(responseData.AccessToken, DateTimeOffset.UtcNow.AddSeconds((double)Int64.Parse(responseData.ExpiresIn)));
                    }
                }
                catch (FormatException)
                {
                    return null;
                }
            }
        }
    }
    catch (WebException)
    {
        //Ignore exception
    }
    catch (IOException)
    {
        //Ignore exception
    }

    return null;
}

Zde je operací POST zavolán request na adresu https://accounts.google.com/o/oauth2/token. V body volání jsou předány parametry code, client_id, client_secret, redirect_uri a grant_type s hodnotou authorization_code. Odpověď je vrácena ve formátu JSON a je zpracována pomoci třídy DataContractJsonSerializer, tím jsou načteny vrácené hodnoty access_token a expires_in (více zde).

Pozn.: Pokud při tomto volání obdržíte chybu 500 - Internal server error jako já, tak jí nejprve zkuste odstranit tím, že si v Google profilu vygenerujete nové ClientID a ClientSecret.

3. Volání Google API

Příklad ASP.NET aplikace si udržuje stejně jako u v případě Windows Live ID nebo Facebooku získaný AccessToken v cookie. Odsud je vyzvednut a použit pro volání Google API na získání informací o přihlášeném uživateli. Kód je ve třídě GoogleAuthClient v metodě RequestUserInfo a vypadá takto:

private static GoogleAuthUser RequestUserInfo(string accessToken)
{
    string url = string.Format(cUserInfoUrlTemplate, accessToken);
    var request = WebRequest.Create(url);

    try
    {
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        if (response != null)
        {
            Stream responseStream = response.GetResponseStream();
            if (responseStream != null)
            {
                try
                {
                    var serializer = new DataContractJsonSerializer(typeof(AuthUser));
                    var user = (AuthUser)serializer.ReadObject(responseStream);
                    if (user != null)
                    {
                        return new GoogleAuthUser(user.ID, user.Name, user.GivenName, user.FamilyName, user.Picture, user.Gender, user.Locale,
                                                    !string.IsNullOrEmpty(user.Email) && user.VerifiedEmail ? user.Email : null, user.link);
                    }
                }
                catch (FormatException)
                {
                    return null;
                }
            }
        }
    }
    catch (WebException)
    {
        //Ignore exception
    }
    catch (IOException)
    {
        //Ignore exception
    }

    return null;
}

Je provedeno GET volání na adresu:
https://www.googleapis.com/oauth2/v1/userinfo?access_token=xxxxxxxxxxxxxxxxxxxxxxxx
Tím je vrácena JSON odpověď, která obsahuje tyto pole (více zde):

  • id – ID přihlášeného uživatele .
  • email – Email uživatele, je vrácen pouze pokud bylo aplikací požadováno a potvrzeno právo scope https://www.googleapis.com/auth/userinfo.email.
  • verified_email – bool příznak, zda byl vrácený email ověřen.
  • name – Celé jméno přihlášeného uživatele.
  • given_name – Křestní jméno přihlášeného uživatele (může být null v případě nezadání uživatelem do profilu).
  • family_name – Příjmení přihlášeného uživatele (může být null v případě nezadání uživatelem do profilu).
  • picture – URL na profilový obrázek  uživatele (může být null v případě nezadání uživatelem do profilu).
  • locale – Registrované locale uživatele, např: ”cs" (může být null v případě nezadání uživatelem do profilu).
  • timezone – Časová zóna přihlášeného uživatele (může být null).
  • gender – Pohlaví (male, female) uživatele (může být null v případě nezadání uživatelem do profilu).
  • link – URL na Google+ profil uživatele, pokud ho má uživatel vytvořen.

Přihlášení jako jiný uživatel

Třída GoogleAuthClient dále obsahuje metodu SignOut pro odhlášení, ta ovšem pouze odstraní držený cookie s access tokenem v naší aplikaci. Nepovedlo se mi provést volání na Google pro odhlášení (jako tomu bylo například v příkladu na Facebook).

Pokud se potřebujeme přihlásit jako jiný uživatel, můžeme provést volání přihlášení pomoci approval_prompt force (viz výše), kde je možné se odhlásit. Druhou možností je přímo zavolat přihlášení jako jiný uživatel (vynutí nejprve odhlášení případně přihlášeného uživatele). To lze provést voláním URL
https://accounts.google.com/o/logout?continue=https://accounts.google.com/o/oauth2/auth?
kde předáme stejný query string jako v případě normálního přihlášení (ale je zde nutné ho předat encodovaně).

Celé URL tedy může vypadat takto:

https://accounts.google.com/o/logout?continue=https://accounts.google.com/o/oauth2/auth?state%3Dprofile%26response_type%3Dcode%26redirect_uri%3Dhttp%253a%252f%252flocalhost%252fGoogleLoginSampleWeb%252foauth2callback%26client_id%3D000000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com%26approval_prompt%3Dauto%26scope%3Dhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%2520https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email

Získání tohoto URL je v příkladu implementováno vlastností LoginDifferentUser.

 

hodnocení článku

2 bodů / 3 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback