英文原文:JavaScript oAuth 編譯:oschina
引言
現在,很多的應用程式都在使用HTML和JavaScript, 這是一個非常明智的選擇,讓你跟上目前的趨勢. 一些主要實體工具因為客戶端驗證和授權等原因提供了API. 當前網站對於驗證的一個廣受歡迎的功能是”單點登入”. 這讓使用者可以通過其它一些社交媒體網站上的身份認證直接登入你的網站. 這篇文章介紹用純JavaScript通過一個簡單的方法讓你從三個身份認證提供者上登入到你的網站.
背景
為了使用身份認證提供者的API, 你要在他們的網站上建立一個應用,完成後它將提供一個API key讓你使用.
- 谷哥 API: https://code.google.com/apis/console/
- Facebook: https://developers.facebook.com/apps
- Twitter: https://dev.twitter.com/apps
使用這些程式碼
如果你不打算長篇閱讀,你可以去直接下載原始碼檔案然後隨便你怎麼使用/修改。
首先,我們包含一些檔案在我們的HTML頁面的頭部。
1 2 3 4 5 |
<!--Register Jquery--> <script src="http://code.jquery.com/jquery-1.9.1.js"></script> <script src="http://code.jquery.com/jquery-migrate-1.1.0.js"></script> <!--Register Google Api--> <script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script> |
最近的時間,Twitter已經廢棄使用可能會導致開發者變得畏畏縮縮的單點客戶端認證。然而,感謝YUI(由Yahoo!提供的API)我們能夠使用Javascript這樣去模擬一個服務端請求到Twitter。所以我們也可以把YUI的庫包含在頭部。
1 2 3 |
<!--Register YUI Api--> <script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui-min.js"></script> |
我們現在建立DOM元素來觸發請求。這些元素可以是你的任意選擇。
1 2 3 |
<div id="fbLogin" onclick="">Facebook</div> <div id="twitterlogin">Twitter</div> <div id="googlelogin">Google</div> |
現在我們看下指令碼。我們從Facebook的登陸開始。
我們要建立的第一個函式用來向 Facebook oAuth API 傳送初始化請,函式將傳送客戶端 ID(由你的Facebook 應用給出),重定向 URL (必須同你註冊應用時填寫的一樣),還有請求型別(此處是訪問令牌)。訪問令牌是使用者驗證所必須的,並也會用來訪問 Facebook 的圖形 API,以及獲取使用者個人資訊。
1 2 3 4 5 6 7 8 9 10 11 |
var appID = <YOUR CLIENT ID>; function fbLogin() { var path = 'https://www.facebook.com/dialog/oauth?'; var queryParams = ['client_id=' + appID, 'redirect_uri=' + window.location, 'response_type=token']; var query = queryParams.join('&'); var url = path + query; window.location.replace(url); } |
相應將是一個附加形如 “#access_token=…….” 的雜湊字串的訪問令牌的到你網站的重定向。要使用訪問令牌,我們現在需要一個檢查 URL 中訪問令牌的函式。同時此函式也將對 Facebook 圖形 API 傳送一個帶有訪問令牌和一個以引數形勢接受使用者資訊的回撥函式的請求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function checkFbHashLogin() { if (window.location.hash.length > 3) { var hash = window.location.hash.substring(1); if(hash.split('=')[0] == 'access_token') { var path = "https://graph.facebook.com/me?"; var queryParams = [hash, 'callback=displayUser']; var query = queryParams.join('&'); var url = path + query; //use jsonp to call the graph var script = document.createElement('script'); script.src = url; document.body.appendChild(script); } } } |
第三步,我們的回撥函式會將使用者資訊轉化為我們可見的形勢。
1 2 3 4 5 6 7 8 9 10 11 12 |
function displayUser(user) { setTimeout(function () { }, 1000); if (user.id != null && user.id != "undefined") { //Do Stuff //You have access to user id, name, username, gender etc. //For more info visit https://developers.facebook.com/docs/ // reference/login/public-profile-and-friend-list } else { alert('user error'); } } |
最後,我們需要一個函式呼叫的觸發器,且我們也需要一個在頁面載入的時候檢查雜湊字串的函式。
1 2 3 4 5 6 7 8 |
$(function () { checkFbHashLogin(); $('#fbLogin').click(function () { fbLogin(); }); }) |
現在我們已完成了Facebook的身份驗證。
首先,我將給出一個帶有解釋運作的註釋的函式。如前所述,我們需要谷歌的客戶端ID,我們的應用必須使用 API 金鑰。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
var clientId = <YOUR CLIENT ID>; var apiKey = <YOUR API KEY>; var scopes = 'https://www.googleapis.com/auth/plus.me'; // Our first function is used to set the api key and // is run once the google api is loaded in the page header. function handleClientLoad() { gapi.client.setApiKey(apiKey); } //Gets the result after the authorization and if successful, //it makes the api call to get the //user's information. function handleAuthResult(authResult) { if (authResult && !authResult.error) { makeApiCall(); } } //Make api call on button click to authorize client function handleAuthClick(event) { gapi.auth.authorize({ client_id: clientId, scope: scopes, immediate: false }, handleAuthResult); return false; } // Load the API and make an API call. Display the results on the screen. function makeApiCall() { gapi.client.load('plus', 'v1', function () { var request = gapi.client.plus.people.get({ 'userId': 'me' }); request.execute(function (resp) { //Do Stuff //You have access to user id, name, display name, gender, emails, etc. //For more info visit https://developers.google.com/+/api/latest/people#resource }); }); } $(function () { var authorizeButton = document.getElementById('googlelogin'); authorizeButton.onclick = handleAuthClick; }) |
這樣就完成了谷歌的認證。
正如之前所說,Twitter API 並不允許純粹的客戶端驗證。因此需要使用 YUI 庫。此庫使用雅虎查詢語言(YQL)制定對Twitter API 的伺服器端請求。
例如,應用中可能使用的一條 YQL 如下:
1 |
select * from twitter.oauth.requesttoken where oauth_callback="<YOUR WEBSITE URL>"; |
你可以看到,select 語句同其它查詢語言的 select 語句一樣。select 語句的條件引數(oauth_callback)是你 Twitter 應用所註冊的 URL。由於我們選擇 URL 匹配,我們並不需要客戶端ID。由於我們使用 JavaScript,我們可以使用 window.location 獲取當前 URL 用於查詢(在程式碼中已處理)。本質上,我們無需關注 YUI 和 YQL。因此,讓我們看看 YUI 庫的實現,以及它是如何呼叫 Twitter API 的。
首先是初始化 YUI 物件。使用此物件,我們將設定所用的模組以及它們的地址。在這裡將使用 Twitter 和 YQL 模組。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
YUI({ combine: false, filter: "raw", debug: false, modules: { 'Twitter': { fullpath: 'js/twitter.js' }, 'myYQL': { fullpath: 'js/yql.js', requires: ['jsonp', 'jsonp-url'] } } }) |
下一步,我們將告知 YUI庫我們將使用資源庫中的哪個元件,並提供回撥函式。我們通過呼叫 YUI 的 “use” 函式完成此操作,只需新增到初始化後的 YUI 物件之後。
1 2 3 |
YUI({ ... }).use('Twitter', 'gallery-storage-lite', 'myYQL', 'node', "event", function (Y) {}); |
回撥函式將在 YUI 庫初始化完成並選定元件之後呼叫,我們將所有處理 Twitter API 使用者驗證的程式碼放置其中。首先要做的是獲取觸發Twitter 使用者驗證的元素,並將點選事件繫結的到一個函式上。這個函式將進行第一次 API 呼叫,獲取 oAuth 請求令牌和金鑰。這些將在一個查詢字串中傳遞到 Twitter 使用者驗證 API,oAuth 令牌驗證將以同樣的方式返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var twtBtn = Y.one('#twitterlogin'); twtBtn.on('click', function (e) { Y.Twitter.call({ type: "request_token" }, function (tokens) { Y.log("step 1"); Y.log(tokens); Y.StorageLite.setItem('oauth_token', tokens.oauth_token); Y.StorageLite.setItem('oauth_token_secret', tokens.oauth_token_secret); window.setTimeout(function () { window.location = "https://twitter.com/oauth/authenticate?oauth_token=" + tokens.oauth_token + "&oauth_token_secret=" + tokens.oauth_token_secret; }, 10); }); }); |
下面幾步將結合巢狀的呼叫和響應,知道我們獲得最終的響應。首先我們將檢查查詢字串以獲取oAuth 令牌驗證。接著令牌和驗證將被傳遞給 YUI Twitter呼叫以獲取訪問令牌。最後,訪問令牌將被髮送到一個呼叫,以索取使用者資訊。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
if (getQueryStringParameter('oauth_token')) { Y.StorageLite.setItem('oauth_token', getQueryStringParameter('oauth_token')); Y.StorageLite.setItem('oauth_verifier', getQueryStringParameter('oauth_verifier')); Y.Twitter.config({ oauth_token: getQueryStringParameter('oauth_token'), oauth_token_secret: getQueryStringParameter('oauth_token_secret') }); Y.Twitter.call({ type: "access_token" }, function (tokens) { Y.Twitter.config({ oauth_token: tokens.oauth_token, oauth_token_secret: tokens.oauth_token_secret }); Y.Twitter.call({ type: "credentials" }, function (user) { Y.Twitter.config({ screen_name: user.screen_name, user_id: user.id }); //Do Stuff //You have access to user id, name, screenname, description, etc. //For more info visit https://dev.twitter.com/docs/api/1.1/get/account/verify_credentials }); }); } |
這將完成 Twitter 認證元件的所有請求。
1 2 3 4 5 6 7 8 9 10 11 12 |
//Supporting function to parse the query string function getQueryStringParameter(key, queryString) { var queryString = queryString || window.location.href; key = key.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regex = new RegExp("[\\?&]" + key + "=([^&#]*)"); var qs = regex.exec(queryString); if (qs) return qs[1]; else return false; } |
兩點
現今,單點登入的使用率正迅速增長,很多大型網站,如雅虎和Hotmail都允許使用者使用單點登入進行驗證。例如,在配置Google API時,你可以將其它供應商同你的 Google API 金鑰繫結。值得注意的是,所有請求都將使用各個驗證提供者應用所登記域名,同時你將需要使用正確的域名和URL網址。因此,應用在你的 Localhost 將無法正常工作。