在Satellizer中将Facebook登录集成到AngularJS App中

本文概述

随着功能丰富的前端框架(例如AngularJS)的出现, 越来越多的逻辑正在前端实现, 例如数据操作/验证, 身份验证等。 Satellizer是AngularJS易于使用的基于令牌的身份验证模块, 它简化了在AngularJS中实施身份验证机制的过程。该库内置了对Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch的支持和Microsoft(Windows Live)帐户。

在本文中, 我们将构建一个非常简单的webapp, 类似于此处的webapp, 你可以登录并查看当前用户的信息。

身份验证与授权

一旦你的应用开始集成用户系统, 你通常会遇到2个可怕的词。根据维基百科:

认证是确认实体声称为真的单条数据(数据)属性的真实性的行为。

授权是指定通常对与信息安全和计算机安全有关的资源的访问权限, 特别是对访问控制的访问权限的功能。

用通俗易懂的术语, 让我们以一个博客网站为例, 其中有人在工作。博主撰写文章, 经理验证内容。每个人都可以向系统进行身份验证(登录), 但是他们的权限(授权)不同, 因此博客作者无法验证内容, 而经理可以。

为什么要使用Satellizer

你可以通过遵循一些教程(例如非常详细的教程)在AngularJS中创建自己的身份验证系统:JSON Web令牌教程:Laravel和AngularJS中的示例。我建议阅读这篇文章, 因为它很好地解释了JWT(JSON Web令牌), 并展示了一种直接使用本地存储和HTTP拦截器在AngularJS中实现身份验证的简单方法。

那为什么要使用Satellizer化器呢?主要原因是它支持少数社交网络登录, 例如Facebook, Twitter等。如今, 尤其是对于在移动设备上使用的网站, 键入用户名和密码非常麻烦, 并且用户希望能够无障碍地使用你的网站。通过使用社交登录。由于集成每个社交网络的SDK并遵循其文档非常重复, 因此以最少的努力支持这些社交登录将是很好的。

此外, Satellizer是Github上的一个活跃项目。主动是此处的关键, 因为这些SDK经常更改, 并且你不希望时不时地阅读其文档(使用Facebook SDK的人都知道这很烦人)

使用Facebook登录的AngularJS应用

这是事情开始变得有趣的地方。

我们将构建一个具有常规登录/注册(即使用用户名, 密码)机制并支持社交登录的网络应用。这个webapp非常简单, 因为它只有3个页面:

  • 主页:任何人都可以看到
  • 登录页面:输入用户名/密码
  • 秘密页面:只有登录用户才能看到

对于后端, 我们将使用Python和Flask。 Python和Flask框架具有很好的表达能力, 因此我希望将代码移植到其他语言/框架不会很困难。当然, 我们将使用AngularJS作为前端。对于社交登录, 我们将仅与Facebook集成, 因为它是当前最受欢迎的社交网络。

开始吧!

步骤1:Bootstrap项目

这是我们构造代码的方式:

- app.py
- static/
	- index.html
- app.js
	- bower.json
	- partials/
		- login.tpl.html
		- home.tpl.html
		- secret.tpl.html

所有的后端代码都在app.py中。前端代码放在static /文件夹中。默认情况下, Flask将自动提供static /文件夹的内容。所有的部分视图都在static / partials /中, 并由ui.router模块处理。

要开始对后端进行编码, 我们需要Python 2.7。*并使用pip安装所需的库。你当然可以使用virtualenv隔离Python环境。以下是放置在requirements.txt中所需的Python模块列表:

Flask==0.10.1
PyJWT==1.4.0
Flask-SQLAlchemy==1.0
requests==2.7.0

要安装所有这些依赖项:

pip install -r requirements.txt

在app.py中, 我们有一些初始代码来引导Flask(为简洁起见, 省略了import语句):

app = Flask(__name__)

@app.route('/')
def index():
    return flask.redirect('/static/index.html')

if __name__ == '__main__':
    app.run(debug=True)

接下来, 我们启动bower并安装AngularJS和ui.router:

bower init # here you will need to answer some question. when in doubt, just hit enter :)
bower install angular angular-ui-router --save # install and save these dependencies into bower.json

安装这些库之后, 我们需要在index.html中包含AngularJS和ui-router并为3个页面创建路由:主页, 登录名和密钥。

<body ng-app="DemoApp">

<a ui-sref="home">Home</a>
<a ui-sref="login">Login</a>
<a ui-sref="secret">Secret</a>
<div ui-view></div>

<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="main.js"></script>
</body>

下面是在main.js中配置路由所需的代码:

var app = angular.module('DemoApp', ['ui.router']);

app.config(function ($stateProvider, $urlRouterProvider) {
  $stateProvider
    .state('home', {
      url: '/home', templateUrl: 'partials/home.tpl.html'
    })
    .state('secret', {
      url: '/secret', templateUrl: 'partials/secret.tpl.html', })
    .state('login', {
      url: '/login', templateUrl: 'partials/login.tpl.html'
    });
  $urlRouterProvider.otherwise('/home');

});

此时, 如果你运行服务器python app.py, 则应该在http:// localhost:5000上具有此基本接口

基本登录界面

此时, “主页”, “登录”和”秘密”链接应该可以正常工作, 并显示相应模板的内容。

恭喜, 你刚刚完成了骨架的设置!如果遇到任何错误, 请在GitHub上检查代码

步骤2:登录和注册

完成此步骤后, 你将拥有一个网络应用程序, 可以使用电子邮件和密码进行注册/登录。

第一步是配置后端。我们需要一个用户模型和一种为给定用户生成JWT令牌的方法。下面显示的用户模型确实得到了简化, 甚至不执行任何基本检查, 例如现场电子邮件是否包含” @”, 或者现场密码是否包含至少6个字符, 等等。

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), nullable=False)
    password = db.Column(db.String(100))

    def token(self):
        payload = {
            'sub': self.id, 'iat': datetime.utcnow(), 'exp': datetime.utcnow() + timedelta(days=14)
        }
        token = jwt.encode(payload, app.config['TOKEN_SECRET'])
        return token.decode('unicode_escape')

我们在python中使用jwt模块在JWT中生成有效负载部分。 iat和exp部分对应于令牌创建和过期的时间戳。在此代码中, 令牌将在2周后过期。

创建用户模型之后, 我们可以添加”登录”和”注册”端点。两者的代码非常相似, 因此在这里我将仅展示”注册”部分。请注意, 默认情况下, Satellizer将分别为”登录”和”注册”调用端点/ auth / login和/ auth / signup。

@app.route('/auth/signup', methods=['POST'])
def signup():
    data = request.json

    email = data["email"]
    password = data["password"]

    user = User(email=email, password=password)
    db.session.add(user)
    db.session.commit()

    return jsonify(token=user.token())

让我们先使用curl检查端点:

curl localhost:5000/auth/signup -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]", "password":"xyz"}'

结果应如下所示:

{
  "token": "very long string…."
}

现在已经准备好后端部分, 让我们来攻击前端!首先, 我们需要安装satellizer并将其添加为main.js中的依赖项:

bower install satellizer --save

添加Satellizer化器作为依赖项:

var app = angular.module('DemoApp', ['ui.router', 'satellizer']);

与到目前为止的所有设置相比, satellizer中的登录和注册实际上非常简单:

$scope.signUp = function () {
    $auth
      .signup({email: $scope.email, password: $scope.password})
      .then(function (response) {
        // set the token received from server
        $auth.setToken(response);
        // go to secret page
        $state.go('secret');
      })
      .catch(function (response) {
        console.log("error response", response);
      })
  };

如果你在设置代码时遇到任何困难, 可以在GitHub上查看代码。

步骤#3:但是秘密视图并不是真正的秘密, 因为任何人都可以看到它!

对, 那是正确的!到现在为止, 任何人都可以不登录而进入秘密页面。

现在是时候在AngularJS中添加一些拦截器了, 以确保如果有人进入了秘密页面并且该用户未登录, 他们将被重定向到登录页面。

首先, 我们应该添加一个标记requiredLogin来区分秘密页面和其他页面。

    .state('secret', {
      url: '/secret', templateUrl: 'partials/secret.tpl.html', controller: 'SecretCtrl', data: {requiredLogin: true}
    })

$ dataChangeStart事件中将使用”数据”部分, 每次路由更改时都会触发该事件:

app.run(function ($rootScope, $state, $auth) {
  $rootScope.$on('$stateChangeStart', function (event, toState) {
      var requiredLogin = false;
      // check if this state need login
      if (toState.data && toState.data.requiredLogin)
        requiredLogin = true;
      
      // if yes and if this user is not logged in, redirect him to login page
      if (requiredLogin && !$auth.isAuthenticated()) {
        event.preventDefault();
        $state.go('login');
      }
    });
});

现在, 用户必须先登录才能直接进入机密页面。

与往常一样, 此步骤的代码可以在此处找到。

步骤#4:是时候获得一些真正的秘密了!

目前, 秘密页面中没有任何真正的秘密。让我们在这里放一些私人的东西。

此步骤开始于在后端中创建一个端点, 该端点只能由经过身份验证的用户访问, 例如具有有效令牌。下面的端点/ user返回与令牌对应的用户的user_id和电子邮件。

@app.route('/user')
def user_info():
    # the token is put in the Authorization header
    if not request.headers.get('Authorization'):
        return jsonify(error='Authorization header missing'), 401
    
    # this header looks like this: "Authorization: Bearer {token}"
    token = request.headers.get('Authorization').split()[1]
    try:
        payload = jwt.decode(token, app.config['TOKEN_SECRET'])
    except DecodeError:
        return jsonify(error='Invalid token'), 401
    except ExpiredSignature:
        return jsonify(error='Expired token'), 401
    else:
        user_id = payload['sub']
        user = User.query.filter_by(id=user_id).first()
        if user is None:
            return jsonify(error='Should not happen ...'), 500
        return jsonify(id=user.id, email=user.email), 200
    return jsonify(error="never reach here..."), 500

同样, 我们利用模块jwt解码”授权”标头中包含的JWT令牌, 并处理令牌过期或无效的情况。

让我们使用curl测试此端点。首先, 我们需要获得一个有效的令牌:

curl localhost:5000/auth/signup -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]", "password":"xyz"}'

然后使用此令牌:

curl localhost:5000/user -H "Authorization: Bearer {put the token here}"

得到以下结果:

{
  "email": "[email protected]", "id": 1
}

现在, 我们需要将此端点包括在Secret Controller中。这非常简单, 因为我们只需要使用常规的$ http模块调用端点即可。令牌由Satellizer自动插入到标头中, 因此我们无需理会保存令牌并将其放入正确标头中的所有细节。

  getUserInfo();

  function getUserInfo() {
    $http.get('/user')
      .then(function (response) {
        $scope.user = response.data;
      })
      .catch(function (response) {
        console.log("getUserInfo error", response);
      })
  }

最后, 我们在秘密页面中拥有真正私人的东西!

秘密页面,显示用户电子邮件和ID。

此步骤的代码在GitHub上。

步骤5:使用Satellizer进行Facebook登录

正如开头提到的, 有关Satellizer的一件好事是, 它使集成社交登录更加容易。在此步骤结束时, 用户可以使用其Facebook帐户登录!

Facebook OAuth身份验证。

首先要做的是在Facebook开发人员页面上创建一个应用程序, 以获取application_id和密码。如果你还没有Facebook开发者帐户, 请按照developers.facebook.com/docs/apps/register创建一个Facebook开发者帐户, 然后创建一个网站应用。之后, 你将具有应用程序ID和应用程序密码, 如下面的屏幕快照所示。

获取应用程序的秘密。

一旦用户选择与Facebook连接, Satellizer就会将授权代码发送到端点/ auth / facebook。使用此授权代码, 后端可以从Facebook / oauth端点检索访问令牌, 该访问令牌允许对Facebook Graph API的调用来获取用户信息, 例如位置, user_friends, 用户电子邮件等。

我们还需要跟踪用户帐户是使用Facebook还是通过常规注册创建的。为此, 我们将facebook_id添加到我们的用户模型。

facebook_id = db.Column(db.String(100)) 

通过我们添加到app.config的环境变量FACEBOOK_SECRET来配置facebook机密。

app.config['FACEBOOK_SECRET'] = os.environ.get('FACEBOOK_SECRET')

因此, 要启动app.py, 你应该设置以下env变量:

FACEBOOK_SECRET={your secret} python app.py

这是处理Facebook登录的方法。默认情况下, Satellizer将调用端点/ auth / facebook。

@app.route('/auth/facebook', methods=['POST'])
def auth_facebook():
    access_token_url = 'https://graph.facebook.com/v2.3/oauth/access_token'
    graph_api_url = 'https://graph.facebook.com/v2.5/me?fields=id, email'

    params = {
        'client_id': request.json['clientId'], 'redirect_uri': request.json['redirectUri'], 'client_secret': app.config['FACEBOOK_SECRET'], 'code': request.json['code']
    }

    # Exchange authorization code for access token.
    r = requests.get(access_token_url, params=params)
    # use json.loads instead of urlparse.parse_qsl
    access_token = json.loads(r.text)

    # Step 2. Retrieve information about the current user.
    r = requests.get(graph_api_url, params=access_token)
    profile = json.loads(r.text)

    # Step 3. Create a new account or return an existing one.
    user = User.query.filter_by(facebook_id=profile['id']).first()
    if user:
        return jsonify(token=user.token())

    u = User(facebook_id=profile['id'], email=profile['email'])
    db.session.add(u)
    db.session.commit()
    return jsonify(token=u.token())

要将请求发送到Facebook服务器, 我们使用方便的模块请求。现在, 后端的困难部分已经完成。在前端, 添加Facebook登录非常简单。首先, 我们需要通过将以下代码添加到app.config函数中来告诉Satellizer我们的facebook_id:

$authProvider.facebook({
    clientId: {your facebook app id}, // by default, the redirect URI is http://localhost:5000
    redirectUri: 'http://localhost:5000/static/index.html'
  });

要使用Facebook登录, 我们可以致电:

$auth.authenticate("facebook")

和往常一样, 你可以在GitHub上检查代码

目前, 该Web应用程序在功能方面已经完成。用户可以使用常规电子邮件和密码或使用Facebook登录/注册。登录后, 用户可以看到其秘密页面。

制作漂亮的界面

此时界面还不是很漂亮, 所以让我们为布局和Angle Toaster模块添加一些Bootstrap, 以很好地处理错误消息, 例如登录失败时。

美化部分的代码可以在这里找到。

总结

本文显示了Satellizer在(简单的)AngularJS Webapp中的逐步集成。借助Satellizer, 我们可以轻松添加其他社交登录信息, 例如Twitter, Linkedin等。前端的代码与本文中的代码完全相同。但是, 后端会有所不同, 因为社交网络SDK的终结点具有不同的协议。你可以查看https://github.com/sahat/satellizer/blob/master/examples/server/python/app.py, 其中包含Facebook, Github, Google, Linkedin, Twiter和Bitbucket的示例。如有疑问, 应查看https://github.com/sahat/satellizer上的文档。

相关:使用区块链的一键式登录:MetaMask教程

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?