AngularJSアプリでのFacebookログインとSatellizerの統合
公開: 2022-03-11AngularJSなどの機能豊富なフロントエンドフレームワークの登場により、データ操作/検証、認証など、ますます多くのロジックがフロントエンドに実装されています。 AngularJS用の使いやすいトークンベースの認証モジュールであるSatellizerは、AngularJSに認証メカニズムを実装するプロセスを簡素化します。ライブラリには、Google、Facebook、LinkedIn、Twitter、Instagram、GitHub、Bitbucket、Yahoo、Twitchのサポートが組み込まれています。 、およびMicrosoft(Windows Live)アカウント。
この記事では、ログインして現在のユーザーの情報を表示できる、ここにあるような非常に単純なWebアプリを作成します。
認証と承認
これらは、アプリがユーザーシステムの統合を開始したときによく遭遇する2つの恐ろしい言葉です。 ウィキペディアによると:
認証とは、エンティティによって真であると主張される単一のデータ(データ)の属性の真偽を確認する行為です。
承認とは、情報セキュリティやコンピュータセキュリティ全般に関連するリソースへのアクセス権、特にアクセス制御へのアクセス権を指定する機能です。
素人の言葉で言えば、何人かの人々がそれに取り組んでいるブログのウェブサイトの例を見てみましょう。 ブロガーは記事を書き、マネージャーはコンテンツを検証します。 各人はシステムに認証(ログイン)できますが、権限(承認)が異なるため、ブロガーはコンテンツを検証できませんが、マネージャーは検証できます。
なぜサテライザー
AngularJSで独自の認証システムを作成するには、次のような非常に詳細なチュートリアルを実行します。JSON Webトークンチュートリアル:LaravelとAngularJSの例。 JWT(JSON Web Token)について詳しく説明し、ローカルストレージとHTTPインターセプターを直接使用してAngularJSで認証を実装する簡単な方法を示しているため、この記事を読むことをお勧めします。
では、なぜサテライザーなのか? 主な理由は、FacebookやTwitterなどの少数のソーシャルネットワークログインをサポートしていることです。最近、特にモバイルで使用されるWebサイトの場合、ユーザー名とパスワードの入力は非常に面倒であり、ユーザーはほとんど支障なくWebサイトを使用できることを期待しています。ソーシャルログインを使用します。 各ソーシャルネットワークのSDKを統合し、それらのドキュメントに従うことは非常に反復的であるため、最小限の労力でこれらのソーシャルログインをサポートすると便利です。
さらに、SatellizerはGithubでアクティブなプロジェクトです。 これらのSDKは頻繁に変更されるため、ここではアクティブが重要です。ドキュメントを時々読みたくない場合もあります(Facebook SDKを使用している人なら誰でも、それがどれほど煩わしいかを知っています)。
Facebookログインを使用したAngularJSアプリ
ここから物事が面白くなり始めます。
通常のログイン/登録(つまり、ユーザー名、パスワードを使用)メカニズムを備え、ソーシャルログインもサポートするWebアプリを構築します。 このWebアプリは、ページが3つしかないため、非常にシンプルです。
- ホームページ:誰でも見ることができます
- ログインページ:ユーザー名/パスワードを入力します
- シークレットページ:ログインしているユーザーのみが表示できる
バックエンドには、PythonとFlaskを使用します。 PythonとフレームワークFlaskは非常に表現力豊かなので、コードを他の言語/フレームワークに移植するのはそれほど難しくないことを願っています。 もちろん、フロントエンドにはAngularJSを使用します。 また、ソーシャルログインについては、現時点で最も人気のあるソーシャルネットワークであるFacebookとのみ統合します。
はじめましょう!
ステップ1:ブートストラッププロジェクト
コードを構成する方法は次のとおりです。
- 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/partial /にあり、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
これらのライブラリをインストールしたら、AngularJSとui-routerをindex.htmlに含め、ホーム、ログイン、シークレットの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:ログインして登録する
このステップを完了すると、電子メールとパスワードを使用して登録/ログインできるWebアプリが作成されます。
最初のステップは、バックエンドを構成することです。 ユーザーモデルと、特定のユーザーの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をそれぞれ「login」と「register」に対して呼び出すことに注意してください。
@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} })
「データ」部分は、ルーティングが変更されるたびに発生する$stateChangeStartイベントで使用されます。
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とeメールを返します。
@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を使用して、「Authorization」ヘッダーに含まれる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 }
次に、このエンドポイントをシークレットコントローラーに含める必要があります。 通常の$httpモジュールを使用してエンドポイントを呼び出す必要があるため、これは非常に簡単です。 トークンはSatellizerによってヘッダーに自動的に挿入されるため、トークンを保存してから正しいヘッダーに配置するための詳細を気にする必要はありません。
getUserInfo(); function getUserInfo() { $http.get('/user') .then(function (response) { $scope.user = response.data; }) .catch(function (response) { console.log("getUserInfo error", response); }) }
最後に、秘密のページに本当に個人的なものがあります!
このステップのコードはGitHubにあります。
ステップ5:Satellizerを使用したFacebookログイン
冒頭で述べたように、Satellizerの良いところは、ソーシャルログインの統合がはるかに簡単になることです。 このステップの最後に、ユーザーは自分のFacebookアカウントを使用してログインできます。
最初に行うことは、 application_idとシークレットコードを取得するために、Facebook開発者ページでアプリケーションを作成することです。 まだ持っていない場合は、developers.facebook.com / docs / apps / registerに従ってFacebook開発者アカウントを作成し、Webサイトアプリを作成してください。 その後、下のスクリーンショットのように、アプリケーションIDとアプリケーションシークレットを取得します。
ユーザーがFacebookに接続することを選択すると、Satellizerは認証コードをエンドポイント/ auth/facebookに送信します。 この認証コードを使用すると、バックエンドはFacebook / oauthエンドポイントからアクセストークンを取得できます。これにより、Facebook Graph APIを呼び出して、場所、user_friends、ユーザーの電子メールなどのユーザー情報を取得できます。
また、ユーザーアカウントがFacebookで作成されたのか、定期的なサインアップで作成されたのかを追跡する必要があります。 そのために、ユーザーモデルにfacebook_idを追加します。
facebook_id = db.Column(db.String(100))
Facebookシークレットは、 app.configに追加する環境変数FACEBOOK_SECRETを介して構成されます。
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関数に追加して、 Facebook_idをSatellizerに通知する必要があります。
$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を使用してログイン/登録できます。 ログインすると、ユーザーは自分の秘密のページを見ることができます。
きれいなインターフェースを作る
この時点ではインターフェイスはあまりきれいではないので、ログインに失敗したときなどのエラーメッセージを適切に処理するために、レイアウト用のBootstrapとAngularToasterモジュールを少し追加しましょう。
この美化部分のコードはここにあります。
結論
この記事では、(単純な)AngularJSWebアプリにSatellizerを段階的に統合する方法について説明します。 Satellizerを使用すると、Twitter、Linkedinなどの他のソーシャルログインを簡単に追加できます。 フロントエンドのコードは、記事とまったく同じです。 ただし、ソーシャルネットワークSDKにはさまざまなプロトコルを持つさまざまなエンドポイントがあるため、バックエンドは異なります。 Facebook、Github、Google、Linkedin、Twiter、Bitbucketの例が含まれているhttps://github.com/sahat/satellizer/blob/master/examples/server/python/app.pyをご覧ください。 疑わしい場合は、https://github.com/sahat/satellizerのドキュメントを参照してください。