2015年5月7日 星期四

Hybrid Apps開發系列之6.1:登入授權OAuth以Facebook為例

OAuth是一種讓第三方取得某用戶登入授權,進而存取該用戶在某網站上所擁有資源的開放標準。簡單說,目前各大網站例如Facebook, Google, Twitter等,都有OAuth登入授權機制,如果想在你的apps裡使用這些網站的資源,便需要實做OAuth。對Ionic Apps而言,OAuth登入授權可使用ngCordova OAuth外掛。該外掛支援Fackbook, Google, Dropbox, Twitter等許多網路服務登入授權,用法也很簡單。底下以Facebook登入授權為例,說明如何在Ionic Apps上取得Facebook內容。

Facebook前置作業:create Facebook App

以OAuth登入前,必須先在Facebook建立對應的App。步驟簡述如下:
  1. 登入FB,前往「管理應用程式」頁面(https://developers.facebook.com/)。
  2. 選取My Apps / Add a New App,接著在跳出的頁面裡選擇「WWW網站」類型。
  3. 圖1.App類型選擇WWW網站
  4. 輸入App名稱,接著點擊「Create New Facebook App ID」。
  5. 根據你的App性質選擇一個類別,再點選「Create App ID」
  6. 圖2.自選類別,再Create App ID
  7. 在Tell us about your website下Site URL, Mobile Site URL都輸入 http://localhost:8100/ 。
  8. 回到My Apps下新建App,選擇側欄選單Settings,在App Domains下輸入localhost。最後複製App ID的內容。此ID將作為ngCordova OAuth程式呼叫的參數。
圖3. Website, App Domains的設定攸關Ionic App能否順利取得FB登入授權。
步驟5,6的設定攸關後續開發的Ionic apps是否能順利取得FB登入授權。

建立Ionic專案!

FB App建好之後,請先建立Ionic專案,並切換到專案資料夾,因為後續的ngCordova OAuth等外掛是安裝在專案內:
ionic start FBOAuth blank
cd FBOAuth

安裝ngCordova OAuth與InAppBrowser外掛

為了完成FB OAuth登入,必須先安裝ngCordova OAuth Plugin。根據ngCordova OAuth Plugin正式文件說明此外掛需要:
  1. Apache Cordova 3.5以上版本。
  2. Apache Cordova InAppBrowser Plug-in
  3. 部分服務登入驗證(如Twitter)還需要加裝jsSHA函式庫。
通常安裝的Apache Cordova版本為4.X版,可在cmd下以
cordova --version
確認之。安裝InAppBrowser外掛,則需輸入:
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git
至於jsSHA因FB並不需要,如有需要安裝,請參考jsSHA

inAppBrowser安裝好之後,便可安裝ngCordova OAuth(若bower未安裝,還必須先以npm安裝bower):
npm install -g bower
bower install ng-cordova-oauth -S
如果執行bower install出現"ENOGIT git is not installed..."錯誤訊息,則還必須進一步安裝Git for Windows (https://msysgit.github.io/)(在Windows作業環境下)。

使用bower成功安裝ngCordova OAuth之後,會出現www/lib/ng-cordova-oauth資料夾。請在index.html加入引用ng-cordova-oauth.js(或ng-cordova-oauth.min.js):
<script src="lib/ng-cordova-oauth/ng-cordova-oauth.min.js">
同時js/app.js內則要注入ngCordovaOauth:
angular.module('starter', ['ionic', 'ngCordovaOauth'])
之後便可使用$cordovaOauth服務進行登入授權。

以$cordovaOauth進行FB登入授權

ngCordova Oauth外掛提供
$cordovaOauth.facebook('你的App ID', appScope, options)
的方式登入。appScope指的是FB的授權項目,請參考FB Permissions。最基本的授權項目有三項:email, user_friends, public_profile。因此實際用法如:
.controller('OauthCtrl', function ($scope, $cordovaOauth) {
    // ...[略]...
    $cordovaOauth.facebook('14399XXXXXXXXXXX', ["email", "user_friends", "public_profile"])
        .then(function(result)...[略]...
下面便以實際範例說明FB OAuth的使用方式。

範例:以OAuth登入授權讀取FB個人資料

範例包含兩個頁面:login.html提供登入畫面,其controller以$cordovaOauth.facebook()啟動登入授權動作。登入授權成功,會取得accessToken,後續以Facebook Graph API讀取FB資料時,必須提供此accessToken;將accessToken儲存起來後,便轉往第2個頁面feed.html。由於程式持續使用accessToken進行FB資料存取,因此此處特別使用ngStorage外掛,建立local儲存空間。feed.html則顯示FB個人動態貼文內容。貼文內容必須以Facebook Graph API的/me/feed取得;另外,登入者的個人資料則是透過Graph API的/me取得。兩個Graph API call都在feed.html的controller內完成。

儲存資料所需:安裝ngStorage

ngStorage用來建立local storage,存取方法簡單,非常適合用來儲存共用資料。其安裝與使用方式與上述ngCordova Oauth外掛雷同,一樣透過bower安裝
bower install ngstorage
也會在專案內建立www/lib/ngstorage資料夾。同樣在index.html要加入該資料夾內的js檔,例如:
<script src="lib/ngstorage/ngStorage.min.js">
在使用時也需注入ngStorage
angular.module('starter', ['ionic', 'ngCordovaOauth','ngStorage'])
最後在程式中再以$localStorage存取資料,存取方式可參考ngStorage或後續js/app.js。

js/app.js

angular.module('starter', ['ionic', 'ngCordovaOauth', 'ngStorage'])
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/login');
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'OauthCtrl'
})
.state('feed', {
url: '/feed',
templateUrl: 'templates/feed.html',
controller: 'feedCtrl'
})
})
.controller('OauthCtrl', function ($scope, $cordovaOauth, $localStorage, $location, $state) {
$scope.fbLogin = function () {
$cordovaOauth.facebook('你的Facebook APP ID',
["email", "user_friends", "public_profile"])
.then(function (result) {
$localStorage.accessToken = result.access_token;
$location.path('/feed');
}, function (error) {
console.warn(error);
})
}
})
.controller('feedCtrl', function ($scope, $http, $localStorage, $location) {
if ($localStorage.hasOwnProperty("accessToken") === true) {
$http.get("https://graph.facebook.com/v2.3/me/feed",
{params: {
access_token: $localStorage.accessToken,
format: "json"
}
})
.then(function (result) {
$scope.feedData = result.data.data;
$http.get("https://graph.facebook.com/v2.3/me",
{params: {
access_token: $localStorage.accessToken,
fields: "picture",
format: "json"
}
})
.then(function (result) {
$scope.feedData.myPicture = result.data.picture.data.url;
});
}, function (error) {
console.log(error);
});
} else { // 未登入
alert('請登入');
$location.path("/login");
}
})
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
});
})
view raw app.js hosted with ❤ by GitHub

  • 第1行:注入ngCordovaOauth與ngStorage。
  • 第16-27行:以$cordovaOauth.facebook()進行登入授權。此處設定email, user_friends, public_profile三個基本權限。此處會帶出FB登入畫面,登入成功則會詢問同不同意授權。點選同意後,會先將FB回傳的access_token儲存在$localStorage.accessToken內,接著轉往下一個畫面(即執行第22行轉至/feed)。
  • 第30-50行:使用Facebook Graph API的/me/feed取得登入者的動態。傳送時必須附上access_token (第32行)。成功的話,第38行繼續送出Graph API的/me,讀取登入者的大頭貼(第41行 field: "picture")。
程式執行畫面如下:
圖4.OAuth機制帶出FB登入畫面與授權畫面,最後程式顯示以自訂格式顯示從FB讀取的個人動態。
其餘檔案如下。其中login.html使用了css/style.css的設定,目的是為了按鈕垂直置中,故在css/style.css內修改了.scroll-content, .scroll兩個css classes之設定。

templates/login.html

<ion-view title="登入">
<ion-content>
<div class="row row-center">
<div class="col col-center">
<button class="button button-positive icon-left ion-social-facebook"
ng-click="fbLogin()">
Facebook登入</button>
</div>
</div>
</ion-content>
</ion-view>
view raw login.html hosted with ❤ by GitHub

templates/feed.html

<ion-view title="Feed">
<ion-content>
<div ng-repeat="data in feedData">
<div class="list card" ng-if="data.hasOwnProperty('message')">
<div class="item item-avatar">
<img ng-src="{{feedData.myPicture}}">
<h2>{{data.from.name}}</h2>
<p>{{data.created_time}}</p>
</div>
<div class="item item-body">
<p>
{{data.message}}
</p>
<p>
<a href="#" class="subdued">{{data.likes.data.length}} Likes</a>
<a href="#" class="subdued">{{data.comments.data.length}} Comments</a>
</p>
</div>
<div class="item tabs tabs-secondary tabs-icon-left">
<a class="tab-item" href="#">
<i class="icon ion-thumbsup"></i>
</a>
<a class="tab-item" href="#">
<i class="icon ion-chatbox"></i>
評論
</a>
<a class="tab-item" href="#">
<i class="icon ion-share"></i>
分享
</a>
</div>
</div>
</div>
</ion-content>
</ion-view>
view raw feed.html hosted with ❤ by GitHub

css/style.css

.scroll-content {
display: table ;
width: 100% ;
height: 100% ;
}
.scroll {
display: table-cell;
vertical-align: middle;
text-align: center;
}
view raw style.css hosted with ❤ by GitHub

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="lib/ngstorage/ngStorage.min.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="lib/ng-cordova-oauth/ng-cordova-oauth.min.js"></script>
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
</body>
</html>
view raw index.html hosted with ❤ by GitHub

沒有留言:

張貼留言