Satellizer와 AngularJS 앱의 Facebook 로그인 통합

게시 됨: 2022-03-11

AngularJS와 같은 기능이 풍부한 프론트엔드 프레임워크의 등장으로 데이터 조작/검증, 인증 등과 같은 프론트엔드에서 점점 더 많은 로직이 구현되고 있습니다. 사용하기 쉬운 AngularJS용 토큰 기반 인증 모듈인 Satellizer는 AngularJS에서 인증 메커니즘을 구현하는 프로세스를 단순화합니다. 라이브러리에는 Google, Facebook, LinkedIn, Twitter, Instagram, GitHub, Bitbucket, Yahoo, Twitch에 대한 지원이 내장되어 있습니다. 및 Microsoft(Windows Live) 계정.

이 기사에서는 로그인하여 현재 사용자의 정보를 볼 수 있는 매우 간단한 웹앱을 구축할 것입니다.

인증 대 권한 부여

앱이 사용자 시스템을 통합하기 시작할 때 자주 접하게 되는 두 가지 무서운 단어입니다. 위키피디아에 따르면:

인증 은 엔터티가 참이라고 주장하는 단일 데이터(데이텀) 속성의 참 여부를 확인하는 행위입니다.

권한 부여 는 일반적으로 정보 보안 및 컴퓨터 보안과 관련된 리소스, 특히 액세스 제어와 관련된 리소스에 대한 액세스 권한을 지정하는 기능입니다.

평신도 용어로 일부 사람들이 작업하는 블로그 웹 사이트의 예를 들어 보겠습니다. 블로거는 기사를 작성하고 관리자는 콘텐츠의 유효성을 검사합니다. 각 사람은 시스템에 인증(로그인)할 수 있지만 권한(권한 부여)이 다르기 때문에 블로거는 콘텐츠를 확인할 수 없지만 관리자는 확인할 수 있습니다.

왜 Satellizer

다음과 같은 매우 상세한 튜토리얼을 따라 AngularJS에서 고유한 인증 시스템을 만들 수 있습니다. JSON 웹 토큰 튜토리얼: Laravel 및 AngularJS의 예. JWT(JSON Web Token)에 대해 잘 설명하고 로컬 저장소와 HTTP 인터셉터를 직접 사용하여 AngularJS에서 인증을 구현하는 간단한 방법을 보여 주는 이 기사를 읽는 것이 좋습니다.

그렇다면 왜 Satellizer인가? 주된 이유는 Facebook, Twitter 등과 같은 소수의 소셜 네트워크 로그인을 지원하기 때문입니다. 요즘 특히 모바일에서 사용되는 웹사이트의 경우 사용자 이름과 비밀번호를 입력하는 것이 상당히 번거롭고 사용자는 웹사이트를 거의 방해받지 않고 사용할 수 있기를 기대합니다. 소셜 로그인을 사용하여. 각 소셜 네트워크의 SDK를 통합하고 문서를 따르는 것이 상당히 반복적이므로 최소한의 노력으로 이러한 소셜 로그인을 지원하는 것이 좋습니다.

또한 Satellizer는 Github에서 활발한 프로젝트입니다. 이러한 SDK는 매우 자주 변경되고 때때로 설명서를 읽고 싶지 않기 때문에 활성이 핵심입니다(Facebook SDK로 작업하는 사람은 이것이 얼마나 성가신지 알고 있습니다)

Facebook 로그인이 있는 AngularJS 앱

여기에서 일이 흥미로워지기 시작합니다.

우리는 일반 로그인/등록(예: 사용자 이름, 비밀번호 사용) 메커니즘이 있고 소셜 로그인도 지원하는 웹 앱을 구축할 것입니다. 이 웹앱은 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/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를 부트스트랩하는 몇 가지 초기 코드가 있습니다(가져오기 문은 간결함을 위해 생략됨).

 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')

파이썬에서 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

종속성으로 sattellizer 추가:

 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단계: 하지만 Secret View는 사실 비밀이 아닙니다. 누구나 볼 수 있기 때문입니다!

네, 맞습니다! 지금까지는 누구나 로그인 없이 비밀 페이지로 이동할 수 있습니다.

누군가가 비밀 페이지로 이동하고 이 사용자가 로그인하지 않은 경우 로그인 페이지로 리디렉션되도록 AngularJS에 인터셉터를 추가해야 합니다.

먼저, 비밀 페이지를 다른 페이지와 구별하기 위해 requiredLogin 플래그를 추가해야 합니다.

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

"data" 부분은 라우팅이 변경될 때마다 발생하는 $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이메일 을 반환합니다.

 @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 }

이제 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 계정을 사용하여 로그인할 수 있습니다!

페이스북 OAuth 인증.

가장 먼저 할 일은 application_id 와 비밀 코드를 갖기 위해 Facebook 개발자 페이지에서 애플리케이션을 만드는 것입니다. 아직 Facebook 개발자 계정이 없다면 developer.facebook.com/docs/apps/register를 팔로우하여 Facebook 개발자 계정을 만들고 웹사이트 앱을 만드세요. 그 후, 아래 스크린샷과 같이 애플리케이션 ID와 애플리케이션 시크릿을 갖게 됩니다.

응용 프로그램 비밀을 가져옵니다.

사용자가 Facebook에 연결하기로 선택하면 Satellizer는 엔드포인트 /auth/facebook 으로 인증 코드를 보냅니다. 이 인증 코드를 사용하여 백엔드는 Facebook 그래프 API에 대한 호출을 허용하여 위치, user_friends, 사용자 이메일 등과 같은 사용자 정보를 얻을 수 있는 Facebook /oauth 엔드포인트에서 액세스 토큰을 검색할 수 있습니다.

또한 사용자 계정이 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 함수에 추가하여 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에서 코드를 확인할 수 있습니다.

현재 웹앱은 기능면에서 완전합니다. 사용자는 일반 이메일과 비밀번호를 사용하거나 Facebook을 사용하여 로그인/등록할 수 있습니다. 로그인하면 사용자는 자신의 비밀 페이지를 볼 수 있습니다.

예쁜 인터페이스 만들기

이 시점에서 인터페이스는 그다지 아름답지 않으므로 레이아웃에 약간의 부트스트랩을 추가하고 로그인 실패와 같은 오류 메시지를 훌륭하게 처리하기 위해 앵귤러 토스터 모듈을 추가해 보겠습니다.

이 아름다운 부분에 대한 코드는 여기에서 찾을 수 있습니다.

결론

이 기사는 (단순한) AngularJS 웹앱에서 Satellizer의 단계별 통합을 보여줍니다. 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의 설명서를 살펴보십시오.

관련: Blockchain을 사용한 원 클릭 로그인: MetaMask 자습서