Využít pro přihlašování účty na sociálních sítích může být dobrá alternativa ke klasickému přihlašování řešenému vlastními silami. Pro uživatele je poměrně nepraktické pamatovat si pro každý web přihlašovací jméno a heslo, a jen velmi málo uživatelů používá pro každou službu různá hesla, což má nepříznivé bezpečnostní dopady. Spousta webů totiž ukládá hesla do databáze v plaintextu a v případě, že by se k databázi někdo dostal, hrozí, že se nabourá i do jiných aplikací. Pravděpodobnost, že uživatel používá stejné jméno a heslo i jinde, není zrovna malá, ne každý si zapamatuje 150 různých hesel a ne každý na správu hesel používá aplikaci (KeePass, Roboform apod.).
Navíc ve spoustě aplikací nepotřebujeme o uživateli vědět mnoho údajů. Často nám stačí pouze určit, že je to ten samý uživatel, co minule, a občas někde potřebujeme zobrazit jeho obrázek a jméno. V takovém případě je zbytečné a pracné implementovat vlastní mechanismy zakládání uživatelských účtů, proceduru pro změnu a obnovení ztraceného hesla atd. Přihlašování pomocí Facebooku nebo jiné sociální sítě či služby tedy může být v mnoha případech užitečné jak pro uživatele (nemusí si pamatovat nové heslo), tak pro vývojáře aplikace (nemusí trávit čas implementací).
Dobrá zpráva je, že přihlašování nejčastějších sociálních sítí a služeb již řeší jedna knihovna z frameworku ASP.NET Web Pages. Třídy, které tuto funkcionalitu zajišťují, můžeme pochopitelně použít i v ASP.NET WebForms či MVC.
Jak přihlašování pomocí externího účtu funguje?
V případě klasického přihlašování pomocí Forms autentizace (komponenta Login v ASP.NET) je princip jasný – uživatel zadá jméno a heslo přímo na našem webu, tlačítkem udělá postback, komponenta Login pomocí membership providera (nebo v události OnLoggingIn) zjistí, jestli je jméno a heslo správné, a pokud ano, vystaví uživateli autentizační ticket. Ticket je zašifrovaná a digiálně podepsaná hodnota, která obsahuje uživatelské jméno a datum platnosti a typicky se ukládá do cookies.
Dokud uživatel v HTTP požadavcích posílá platný ticket, ASP.NET aplikace jej považuje za přihlášeného, a fungují nám všechny mechanismy funkcí Membership.GetUser() počínaje, přes Page.User.Identity.IsAuthenticated až po komponenty LoginView a LoginStatus.
Přihlašování pomocí Facebooku (anebo jiných služeb používajících OAuth autentizaci) funguje takto:
- Přesměrujeme uživatele na přihlašovací stránku, která je na doméně facebook.com. Typicky v URL této stránky pošleme adresu, kam nás má Facebook vrátit v případě, že se přihlašování podaří.
- Uživatel se na této stránce přihlásí, Facebook ověří, jestli je jméno a heslo správné, ještě si typicky od uživatele nechá potvrdit, že chce povolit určitá oprávnění vaší aplikaci.
- Následně je uživatel přesměrován zpět do naší aplikace na cílovou stránku a v URL parametrech najdeme informace o tom, zda-li se přihlášení povedlo. V URL také najdeme takzvaný access token, což je autentizační ticket Facebooku. Tento token se nám bude hodit, pokud budeme chtít číst nějaká data z Facebook Graph API – například jméno aktuálního uživatele, seznam přátel atd.
- V neposlední řadě v URL najdeme zakódované ID uživatele, které používá Facebook. Podle něj dohledáme uživatele v databázi naší aplikace a přihlásíme jej tak, že mu vystavíme klasický autentizační ticket. Tím zajistíme kompatibilitu s předchozím postupem. Jediný údaj, který pro vystavení autentizačního ticketu potřebujeme, je uživatelské jméno. V případě, že naše aplikace nemá v databázi tabulku uživatelů a nepoužívá ani membership providera, můžeme jako uživatelské jméno použít rovnou ID uživatele z Facebooku.
Krok 1: Přidání knihovny Microsoft WebPages OAuth
Nejprve musíme do projektu přidat knihovnu Microsoft Web Pages OAuth. Nejjednodušší způsob je použít balíčkovací systém NuGet (je součást Visual Studia 2012, do verze 2010 je jej potřeba doinstalovat). Stačí pravým tlačítkem kliknout na projekt v Solution Exploreru a zvolit Manage NuGet Packages. Nalevo zvolíme sekci Online a do vyhledávacího okénka v pravém horním rohu napíšeme “web pages”.
Instalace chvíli trvá, neboť knihovna má poměrně dost závislostí. NuGet stáhne všechny potřebné knihovny a dá je do referencí projektu.
Krok 2: Založení aplikace na Facebooku
Abychom se proti Facebooku mohli autentizovat, musíme dále založit novou aplikaci a získat Application ID a Application Secret. Přihlaste se tedy na portál http://developer.facebook.com a nahoře klikněte na záložku Apps. Dále klikněte na tlačítko Vytvořit novou aplikaci. Je třeba zadat název aplikace, který se bude zobrazovat uživatelům, a dále unikátní id aplikace, které mělo obsahovat jen malá písmena.
Po proklikání průvodce (bude chtít ještě opsat text z obrázku) se nám vytvoří nová aplikace. Protože budeme přihlašování testovat, je vhodné jej hned povolit a zadat doménu, na níž aplikace poběží. Protože si s tím budeme hrát na localhostu, jako adresu pro návrat zadáme URL, na níž nám aplikace běží ve Visual Studiu, v mém případě tedy http://localhost:52522/Login.ashx. Login.ashx bude handler, na který nás Facebook přesměruje, a kde zjistíme, jak operace dopadla.
Nyní pro nás budou důležitá pole App ID a App Secret, které budeme potřebovat v následujícím kroku. App Secret uchovávejte v tajnosti, pokud by došlo k jeho kompromitaci, vyresetujte jej příslušným odkazem a upravte v aplikaci.
Krok 3: Registrace providera v aplikaci
Do naší webové aplikace přidáme soubor Global.asax (pravým tlačítkem klikneme na projekt, zvolíme Add New Item a v seznamu vybereme Global Application Class). Upravíme metodu Application_Start následujícím způsobem:
protected void Application_Start(object sender, EventArgs e)
{
RegisterAuthenticationProviders();
}
///
/// Registers the authentication providers.
///
private void RegisterAuthenticationProviders()
{
Microsoft.Web.WebPages.OAuth.OAuthWebSecurity.RegisterFacebookClient("sem doplnit appId", "sem doplnit appSecret", "Facebook");
}
Nezapomeňte do kódu doplnit správné AppId a AppSecret z kroku 2, doporučuji tyto hodnoty dát do konfiguračního souboru, třeba do sekce appSettings. Pro účely ladění budete možná chtít používat jinou Facebook aplikaci než pro produkční prostředí, například kvůli nastavení domén a cílové stránky po přihlášení.
Krok 4: Přihlašovací stránka
Nyní místo přihlašovacího dialogu (nebo vedle něj, pokud chcete zachovat obě možnosti) umístíme tlačítko, které nás přesměruje na přihlašovací stránku Facebooku. Toto tlačítko bude volat následující funkci.
protected void FacebookLink_OnClick(object sender, EventArgs e)
{
Microsoft.Web.WebPages.OAuth.OAuthWebSecurity.RequestAuthentication("Facebook", "~/Login.ashx");
}
Prvním parametrem funkce je ID providera, v našem případě Facebook. Knihovna Web Pages OAuth totiž podporuje kromě Facebooku další sítě, například Twitter nebo Windows Live ID. Druhým parametrem je URL, na níž máme být po příhlášení navráceni.
Tato funkce přesměruje uživatele na web Facebooku, kde se přihlásí, a následně nás vrátí zpět do naší aplikace, kde musíme výsledek přihlášení zpracovat.
Pozor, Facebook kontroluje, že se chcete vrátit na stejnou stránku, která je uvedena v detailu aplikace. Do returnUrl ale můžete přidávat URL parametry, což se hodí, pokud potřebujete přenést nějaké informace přes proces přihlášení.
Krok 5: Dokončení přihlášení
Přidáme do projektu handler Login.ashx (pravým tlačítkem na projekt, Add New Item a vybrat Generic Handler) a do metody ProcessRequest umístíme následující kód:
var result = Microsoft.Web.WebPages.OAuth.OAuthWebSecurity.VerifyAuthentication();
if (result.IsSuccessful)
{
// přihlášení úspěšné
var userId = result.ProviderUserId;
// TODO: dohledat uživatele v databázi podle ID, případně mu založit účet
// přihlásit uživatele
FormsAuthentication.SetAuthCookie(username, true);
context.Response.Redirect("~/Default.aspx");
}
else
{
// přihlášení se nezdařilo
context.Response.Redirect("~/LoginFailed.aspx");
}
Nejprve zavoláme funkci VerifyAuthentication, která se podívá do URL a rozparsuje parametry. Ve vlastnosti result.IsSuccessful pak zjistíme, zda-li jsme byli přihlášeni úspěšně. Logika, co dál dělat, pak už závisí na naší aplikaci.
Pokud máme někde v databázi seznam uživatelů, pak podle result.ProviderUserId, což je unikátní ID uživatele v rámci Facebooku, najdeme příslušného uživatele a pomocí funkce FormsAuthentication.SetAuthCookie mu vygenerujeme do cookie autentizační ticket, čímž jej přihlásíme. Pokud se přes Facebook přihlásil uživatel, kterého ještě neznáme, měli bychom mu účet založit, to opět závisí na logice aplikace. Je také možné, že v databázi seznam uživatelů vůbec uchovávat nechcete, pak stačí uživatele přihlásit a jako uživatelské jméno do funkce SetAuthCookie klidně můžeme přiřadit např. result.ProviderUserId. Tady chování záleží na aplikaci samotné.
Pokud se přihlášení nezdařilo, je vhodné o tom uživatele informovat a nabídnout mu, aby to zkusil znovu. V ukázce kódu přesměrujeme na stránku LoginFailed.aspx.
Krok 6: Zjištění jména uživatele a profilového obrázku
Zjistit URL profilového obrázku uživatele není nic těžkého, URL je v následujícím formátu:
var userImageUrl = "https://graph.facebook.com/" + result.ProviderUserId + "/picture?type=large";
Velikost obrázku určujete parametrem type – přípustné hodnoty jsou square, small, normal a large, podrobněji je to popsáno
v dokumentaci Facebooku.
Ke zjištění jména uživatele musíme použít Graph API – v dokumentaci se dočteme, že údaje o aktuálním uživateli najdeme na adrese https://graph.facebook.com/me. Pro použití této adresy ale musíme poslat ještě access token, což se dělá přidáním parametru access_token do URL. Pokud na takovouto adresu uděláme GET požadavek, Facebook nám vrátí informace o aktuálním uživateli (podle access tokenu) ve formátu JSON. Pak už jen stačí vytáhnout atribut name z odpovědi Facebooku a máme vyhráno.
Access token najdeme v proměnné result.ExtraData pod klíčem accesstoken.
// získat access token, který se používá pro dotazy v Graph API
var accessToken = result.ExtraData["accesstoken"];
// stáhnout detaily o aktuálním uživateli
var wc = new WebClient();
var data = wc.DownloadString("https://graph.facebook.com/me?access_token=" + accessToken);
// rozparsovat
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
dynamic parsed = serializer.DeserializeObject(data);
var userDisplayName = parsed["name"] as string;
Pokud potřebujete s Graph API komunikovat i jinde, než jen v handleru Login.ashx, je potřeba si access token někam uložit. Doporučuji jej uložit do databáze k příslušnému uživateli.
Pokud si chcete práci s Graph API usnadnit, doporučuji přidat do projektu NuGet balíček Facebook (www.facebooksdk.net). Zaslání požadavku a deserializaci JSONu za vás udělá sám a na jeden řádek kódu.
Přepnutí do produkčního prostředí
Jakmile budete mít aplikaci hotovou a nasazenou na finální URL, vraťte se na http://developer.facebook.com a přepněte aplikaci ze sandbox módu do ostrého režimu. Dále pak upravte adresu v sekci Přihlašování.
Podpora dalších sociálních sítí
Knihovna Web Pages OAuth umí i další providery, např. Twitter, LinkedIn, Microsoft Live ID nebo Google ID. Postup je obdobný – v Global.asax použijete k zaregistrování providera příslušnou metodu a zadáte application id a secret, které získáte na následujících stránkách:
A nakonec ve funkci RequestAuthentication do prvního parametru dáte ID providera, kterého chcete použít.
V tomto článku jsme si krok za krokem ukázali, jak napojit ASP.NET aplikaci na přihlašování pomocí externích účtů knihovnou Web Pages OAuth. Po návratu z přihlašovací stránky jsme uživateli vystavili klasický autentizační ticket, takže můžeme externí účty kombinovat s klasickým přihlašováním pomocí komponenty Login.