第四课:使用Facebook做授权验证

本节课中我们将整合Ionic Native中的Facebook插件,这样用户就可以在应用中获得认证,同时我们也可以做其他的事情例如获得用户信息。使用Facebook可以做大把的事情,我不会一一赘述,你还是看文档来的爽快些。
使用类似Facebook API类似的社交认证给我们带来了大量的好处。他帮助我们节省了时间去创建自己的认证后端服务(这里面包括了创建数据库,存储用户安全证书,操作密码重设逻辑等等),他帮助用户节省了创建新帐户的精力(他们只要一键就可以登录了),他提供了大量好用的数据和整合。这也不是说社交登录同源是最佳的认证方法,但是他的优点也很明显。
我们来研究一下如何设置Facebook插件然后将他整合到我们的应用中来。
重要:Facebook连接插件只会在真机上运行的时候在有效,如果你在桌面浏览器中运行的时候只会受到错误。用ionic run android或者ionic run ios代替ionic serve。如果你不确定怎么样才能让应用在你的设备上运行的话,先看一下本书的测试与调试部分。

设置Facebook应用

之前课程讲过,这个插件跟普通插件安装不一样。我们在安装的时候需要给插件提供一个App Name和一个App ID。所以我们需要在Facebook开发者平台创建一个应用,我们先来进行这一步。
首先你需要去developers.facebook.com如果没有帐号的话麻烦先注册一个。如果做完这一步的话,你应该可以看到如下:
Facebook开发者中心
点击My Apps然后Add a New App。选择iOS平台,然后在下一页上点击右上角的Skip and Create App ID按钮。填好Display Name(你的应用的名字,我们现在假定是CamperChat)并选择一个分类。然后点击Create App ID
Facebook开发者中心
现在你应该来到这样的一个屏幕。
Facebook开发者中心
你应该可以看到一个域叫做App ID,把他记在本子上因为我们马上就要用到他了。我们还需要一些设置。点击左边的Settings标签,在此我们将要添加使用平台,也就是iOS和Android。
我先现在可以添加iOS平台,但是Android平台在保存之前需要一个“key hash”。所以,我们现在不理他了,但是后面一定要回来加好因为没有他Android平台将无法运行。我们将在后面的构建章节学习如何为Android创建一个keystore文件和一个key hash,所以如果你现在就像完成这一步的话,可以现在就去到 Signing Android Applications部分。
点击Add Platform按钮然后选择iOS。你需要添加一个Bundle ID大概是这样的格式com.你的名字字母.你的项目或者com.你的公司.你的项目或者其他类似的东西。(译者:注意,一定要用字母,不要让我后悔把包名翻译了一下)同时你也需要确保将Single Sign On为‘Yes’。
同时需要确保你提供的Bundle ID和你的Ionic项目中的config.xml中的一致,所以确认一下你的config.xml下面这一行是否跟你的Facebook Apps Bundle ID匹配:

  1. <widget id="com.yourname.yourproject" version="0.0.1"
  2. xmlns="http://www.w3.org/ns/widgets"
  3. xmlns:cdv="http://cordova.apache.org/ns/1.0">

在后面将你的Facebook app添加Android平台的时候也要提供相同的Bundle ID(他应该是在Google Play Package Name下面添加的)。
这是目前为止能做的,App NameApp ID在手,我们就可以给应用安装插件了。
重要:当你的应用准备上线的时候,记得将Facebook应用切换出开发模式,也就是去App Review标签页切换“Make Your App Public?”为“Yes”。

安装Facebook连接插件

在应用中安装此插件的话需要在项目目录内运行如下命令:

  1. ionic plugin add cordova-plugin-facebook4 --save --variable APP_ID="123456789" --variable APP_NAME="myApplication"

记得将APP_ID和APP_NAME替换成你自己刚创建的的Facebook应用的。
重要:目前在Andoid上这个插件还有一个构建问题。根据你使用的版本这个可能也可能不会影响到你,但是如果构建Android失败的话,你可能需要去更改platforms/android/project.properties这一行:

  1. cordova.system.library.1=com.facebook.android:facebook-android-sdk:4.4.0

设置认证

我们现在设置好了我们所需的东西,我们现在可以进行一点点编码工作了。整合Ionic Native的Facebook API其实非常简单,但是在这之前我们先创建我们的数据服务这样我们可以临时存储一些Facebook的相关值。数据服务主要是用于处理存储和获取我们的信息数据,但是由于我们需要存储一些来自Facebook的数据,所以很容易在这里确定好。
> 修改 src/providers/data.ts 为如下:

  1. import { Injectable } from '@angular/core';
  2. @Injectable()
  3. export class Data {
  4. fbid: number;
  5. username: string;
  6. picture: string;
  7. constructor() {
  8. }
  9. }

现在,我们要对登录页进行一些修改,以让用户在点击登录按钮的时候通过Facebook验证,而不是直接去到主页。
> 修改 src/pages/login/login.ts 的 login 函数如下:

  1. login(): void {
  2. Facebook.login(['public_profile']).then((response) => {
  3. this.getProfile();
  4. }, (err) => {
  5. let alert = this.alertCtrl.create({
  6. title: 'Oops!',
  7. subTitle: 'Something went wrong, please try again later.',
  8. buttons: ['Ok']
  9. });
  10. alert.present();
  11. });
  12. }

由于我们已经从Ionic Native导入过Facebook,我们现在可以访问Facebook对象了。我们调用login方法并传入我们请求的权限数组。我们只需要基本用户信息,所以我们只请求了用户的“public profile”权限,其他一些可以请求的权限例如:

  • 用户朋友
  • 用户兴趣
  • 用户简介
  • 用户位置
  • 用户打标签地方

还有其他一大堆,想要知道的话,点我吧login函数返回一个promise,所以我们给响应设置了一个处理器,如果成功的话我们触发之前设置的getProfile函数,这个函数将启动主页。如果不成功的话,我们创建一个警告框并展示给用户。
我们现在知道用户成功通过Facebook认证,他们也连接到我们的应用了,但是我们还是需要搞清楚一些细节。为了让他们能够用上我们的应用,我们需要他们的名字和照片,为了获取这些信息我们需要需改getProfile函数。
> 修改 src/pages/login/login.ts 的 getProfile 函数如下:

  1. getProfile(): void {
  2. Facebook.api('/me?fields=id,name,picture', ['public_profile']).then((response) => {
  3. console.log(response);
  4. this.dataService.fbid = response.id;
  5. this.dataService.username = response.name;
  6. this.dataService.picture = response.picture.data.url;
  7. this.menu.enable(true);
  8. this.nav.setRoot(HomePage);
  9. },
  10. (err) => {
  11. console.log(err);
  12. let alert = this.alertCtrl.create({
  13. title: 'Oops!',
  14. subTitle: 'Something went wrong, please try again later.',
  15. buttons: ['Ok']
  16. });
  17. alert.present();
  18. });
  19. }

现在我们想Facebook插件提供的api发起了调用。他允许我们与 Facebook Graph API 交互这就是我们能用Facebook做的所有事情了 — 你可以做一些比较复杂的东西了但是我们只是用它来获取用户id,全名和展示图片。
第一个需要提供给api调用的参数是需要访问的终端,当前对我们来说就是/me因为我们想要摘掉当前登录用户的数据,我们添加了一个查询字符串包含了所有我们想要返回的数据域。我们也提供了一个权限数组然后等待响应。
如果响应成功的话我们使用我们的dataService存储得到的数据,然后我们启用侧滑菜单并转到主页。如果返回不成功的话,我们就要再次给用户展示一个警告框并把停留在登录页。
另一个需要用到的功能是Facebook API的登出方法。当用户登出我们的应用的时候我们也需要Facebook终止本次会话(session)(他不会登出facebook,只是再次使用的时候需要通过Facebook再次重新认证)。所以我们修养修改我们的logout函数。
> 修改 src/app/app.module.ts的logout方法如下:

  1. logout(): void {
  2. this.menu.close();
  3. this.menu.enable(false);
  4. this.nav.setRoot(LoginPage);
  5. this.dataService.fbid = null;
  6. this.dataService.username = null;
  7. this.dataService.picture = null;
  8. Facebook.logout();
  9. }

首先我们处理我们这边的事情。我们关闭了菜单并禁用了他,然后切换回登录页。我们重置了所有存放在我们数据服务是的Facebook数据,然后我们调用了Facebook API的logout方法。现在用户应该在咱们的应用中回到了登录页并且是未认证状态。
由于用户在认证的时候会有一点点的等待时间(就像我们获取用户资料的时候一样),我们想要给用户展示正在发生着一些事情,而不是应用卡死了。我们会用Ionic的LoadingController服务来完成这个。他允许我们在一个时期内停止和应用交互。
> 修改 src/pages/login/login.ts 为如下:

  1. import { Component } from '@angular/core';
  2. import { Platform, NavController, MenuController, AlertController, LoadingController } from 'ionic-angular';
  3. import { Facebook } from 'ionic-native';
  4. import { HomePage } from '../home/home';
  5. import { Data } from '../../providers/data';
  6. @Component({
  7. selector: 'page-login',
  8. templateUrl: 'login.html'
  9. })
  10. export class LoginPage {
  11. loading: any;
  12. constructor(public nav: NavController, public platform: Platform, public menu: MenuController, public dataService: Data, public alertCtrl:AlertController, public loadingCtrl: LoadingController) {
  13. this.loading = this.loadingCtrl.create({
  14. content: 'Authenticating...'
  15. });
  16. this.menu.enable(false);
  17. }
  18. login(): void {
  19. this.loading.present();
  20. Facebook.login(['public_profile']).then((response) => {
  21. this.getProfile();
  22. }, (err) => {
  23. let alert = this.alertCtrl.create({
  24. title: 'Oops!',
  25. subTitle: 'Something went wrong, please try again later.',
  26. buttons: ['Ok']
  27. });
  28. this.loading.dismiss();
  29. alert.present();
  30. });
  31. }
  32. getProfile(): void {
  33. Facebook.api('/me?fields=id,name,picture', ['public_profile']).then((response) => {
  34. console.log(response);
  35. this.dataService.fbid = response.id;
  36. this.dataService.username = response.name;
  37. this.dataService.picture = response.picture.data.url;
  38. this.menu.enable(true);
  39. this.loading.dismiss();
  40. this.nav.setRoot(HomePage);
  41. },
  42. (err) => {
  43. console.log(err);
  44. let alert = this.alertCtrl.create({
  45. title: 'Oops!',
  46. subTitle: 'Something went wrong, please try again later.',
  47. buttons: ['Ok']
  48. });
  49. this.loading.dismiss();
  50. alert.present();
  51. });
  52. }
  53. }

注意在这里我们导入了LoadingController服务,我们在构造器中设置了一个“Authenticating…”信息。然后我们在调用登录方法的时候呈现了这个加载信息(就像Alert或者Modal一样)。然后,在响应的时候不管返回成功失败我们都关闭了加载中的信息。
这就是应用整合Facebook的全部了,但是可以通过Facebook API能做的远远不止这些。建议你看一下插件文档Facebook Graph API了解更多。
下节课中,我们来研究怎么样向屏幕上发送信息。