SSO 버튼을 만드는 방법 – Flask 로그인 자습서

게시 됨: 2022-03-11

응용 프로그램은 사용자가 데이터를 저장하거나 자신의 프로필을 만들거나 중요한 리소스에 대한 액세스를 제한하기 위해 로그인 기능이 필요한 경우가 많습니다. 최신 앱에서 사용자는 이메일 확인, 비밀번호 재설정 또는 다단계 인증과 같은 표준 로그인 관련 기능을 기대합니다. 이러한 기능은 필요하지만 제대로 사용하기 쉽지 않으며 일반적으로 앱의 주요 비즈니스가 아닙니다.

사용자 측에서는 또 다른 이메일 및 비밀번호 쌍을 만들고 기억해야 하기 때문에 긴 등록 프로세스를 원하지 않을 수 있습니다. 적절한 암호 관리자가 없으면 사용자는 보안 면에서 끔찍한 동일한 암호를 재사용하는 경향이 있습니다.

소셜 미디어 버튼이 있는 로그인으로 대부분 사용자에게 알려진 SSO(Single Sign-On)는 이 문제에 대한 솔루션으로 개발되었습니다. 사용자에게는 또 다른 번거로운 등록 절차를 거치지 않는 것이 쉬웠습니다. 기업의 경우 사용자의 마찰을 제거하는 것은 항상 큰 승리이며 개발자의 경우 이제 모든 로그인 관련 기능이 ID 제공자(Facebook, Google, Twitter 등)에 위임 되므로 코드가 줄어듭니다! 앱은 사용자 ID를 확인하는 작업을 수행하는 ID 공급자를 신뢰 합니다.

SSO는 일반적으로 OIDC(OpenId Connect) 또는 SAML 프로토콜에 의해 구동됩니다. SAML은 주로 엔터프라이즈 애플리케이션에서 사용됩니다. OIDC는 OAuth2를 기반으로 하며 Facebook, Google 등과 같은 소셜 ID 제공업체에서 사용합니다. 이 게시물에서는 OIDC/OAuth2 프로토콜에 중점을 둘 것입니다.

이 Flask 로그인 자습서에서는 SimpleLogin 및 Facebook을 ID 공급자로 사용하여 Flask 애플리케이션에 SSO 로그인 버튼을 추가하는 단계별 가이드를 작성합니다. 이것은 외부 라이브러리를 사용하지 않고 수행할 수 있지만 OAuth의 복잡성을 단순화하기 위해 라이브러리인 Requests-OAuthlib를 사용하여 OAuth 공급자를 통합합니다. SSO를 처음부터 구현하는 데 관심이 있는 경우 SSO 로그인 구현 - 원시 방법 을 확인하세요.

이 문서가 끝나면 다음 페이지가 있는 Flask 앱이 있어야 합니다.

  • 로그인 버튼이 있는 홈페이지
  • 로그인에 성공하면 사용자가 이름, 이메일 및 아바타와 같은 정보를 볼 수 있는 사용자 정보 페이지

이 튜토리얼의 모든 코드는 flask-social-login-example 리포지토리에서 찾을 수 있습니다.

여기에서 데모도 사용할 수 있습니다. Glitch에서 코드를 자유롭게 리믹스하십시오.

1단계: 부트스트랩 플라스크 앱

flaskRequests-OAuthlib 를 설치합니다. virtualenv 또는 pipenv 를 사용하여 환경을 격리할 수도 있습니다.

pip 설치 플라스크 requests_oauthlib

app.py 와 홈 페이지에 로그인 버튼을 표시하는 경로를 만듭니다.

 import flask app = flask.Flask(__name__) @app.route("/") def index(): return """ <a href="/login">Login</a> """ if __name__ == '__main__': app.run(debug=True)

이 앱을 실행하고 모든 것이 잘 작동하는지 확인합시다.

 python app.py

http://localhost:5000을 열 때 이 페이지가 표시되어야 합니다. 전체 코드는 step1.py에 있습니다.

SimpleLogin으로 로그인

2단계: ID 제공자 자격 증명

현재 수백(수천은 아닐지라도)의 ID 제공자가 있으며 가장 인기 있는 것은 Facebook, Google, GitHub 및 Instagram입니다. 이 게시물에서는 개발자 친화성 때문에 SimpleLogin을 선택했습니다. 그러나 동일한 코드가 모든 OAuth2 ID 제공자와 함께 작동합니다. (면책 조항: 저는 SimpleLogin의 공동 설립자입니다. 에헴은 제가 사용하기로 결정한 한 요인이었을 수 있습니다.)

SimpleLogin으로 이동하여 계정이 아직 없는 경우 계정을 만든 다음 개발자 탭에서 새 앱을 만드십시오.

앱 상세 페이지에서 AppID와 AppSecret을 복사하여 변수 환경에 저장해 주세요. OAuth 용어에서 클라이언트는 실제로 타사 앱, 즉 귀하의 앱을 의미합니다. 이러한 값을 코드에 직접 넣을 수 있지만 자격 증명을 환경 변수에 저장하는 것이 좋습니다. 이것은 또한 열두 가지 요소의 세 번째 요소이기도 합니다.

OAuth2 설정

 export CLIENT_ID={your AppID} export CLIENT_SECRET={your AppSecret}

app.py 에서 파일 상단에 다음 행을 추가하여 client idclient secret 을 얻으십시오.

 import os CLIENT_ID = os.environ.get("CLIENT_ID") CLIENT_SECRET = os.environ.get("CLIENT_SECRET")

다음 단계에서 사용할 이러한 OAuth URL도 app.py 상단에 추가하세요. OAuth 엔드포인트 페이지에서 복사할 수도 있습니다.

 AUTHORIZATION_BASE_URL = "https://app.simplelogin.io/oauth2/authorize" TOKEN_URL = "https://app.simplelogin.io/oauth2/token" USERINFO_URL = "https://app.simplelogin.io/oauth2/userinfo"

지금 SSL 설정에 대해 걱정하고 싶지 않으므로 일반 HTTP를 사용해도 Requests-OAuthlib 에 알려줍시다.

 # This allows us to use a plain HTTP callback os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

평소와 같이 이 단계의 코드는 step2.py에 있습니다.

3단계: 로그인 리디렉션

사용자가 로그인 버튼을 클릭하면:

  1. 사용자는 사용자가 자신의 정보를 앱과 공유할 것인지 묻는 ID 로그인 공급자 인증 페이지로 리디렉션됩니다.
  2. 사용자가 승인되면 나중에 서비스 공급자로부터 사용자 정보를 얻을 수 있는 access token 과 교환하는 데 앱이 사용할 URL의 code 와 함께 앱의 페이지로 다시 리디렉션됩니다.

따라서 두 가지 경로가 필요합니다. 사용자를 ID 제공자로 리디렉션하는 login 경로와 code 를 수신하고 이를 access token 으로 교환하는 callback 경로입니다. 콜백 경로는 사용자 정보를 표시하는 역할도 합니다.

 @app.route("/login") def login(): simplelogin = requests_oauthlib.OAuth2Session( CLIENT_ID, redirect_uri="http://localhost:5000/callback" ) authorization_url, _ = simplelogin.authorization_url(AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url) @app.route("/callback") def callback(): simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID) simplelogin.fetch_token( TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url ) user_info = simplelogin.get(USERINFO_URL).json() return f""" User information: <br> Name: {user_info["name"]} <br> Email: {user_info["email"]} <br> Avatar <img src="{user_info.get('avatar_url')}"> <br> <a href="/">Home</a> """

로그인 버튼을 클릭하면 다음과 같은 흐름이 나타납니다. 전체 코드는 GitHub의 step3.py에서 찾을 수 있습니다.

SimpleLogin으로 로그인하여 사용자 정보 허용

페이스북으로 로그인

Facebook, Google 및 Twitter 로그인 설정은 약간 복잡하며 SSL 설정 또는 올바른 범위 선택과 같은 추가 단계가 필요합니다. 이것들은 이 문서의 범위를 벗어납니다.

정교한 UI 외에도 Facebook 통합에서 가장 어려운 부분은 Facebook SDK의 새 버전이 로컬 일반 HTTP를 허용하지 않기 때문에 HTTPS에서 로컬로 웹 앱을 제공하는 방법을 찾는 것일 수 있습니다. 빠른 HTTPS URL을 사용하려면 무료 도구인 Ngrok을 사용하는 것이 좋습니다.

1단계: Facebook 앱 만들기

https://developers.facebook.com 으로 이동하여 새 앱을 만드세요.

새 앱 ID 만들기

그런 다음 다음 화면에서 "Facebook 로그인 통합"을 선택합니다.

Facebook 로그인 통합

2단계: Facebook OAuth 자격 증명

왼쪽의 "설정/기본"을 클릭하고 앱 ID앱 비밀번호 를 복사합니다. 그들은 실제로 OAuth client-idclient-secret 입니다.

기본 설정

client-idclient-secret 를 업데이트합니다.

 export FB_CLIENT_ID={your facebook AppId} export FB_CLIENT_SECRET={your facebook AppSecret}

AUTHORIZATION_BASE_URL 및 TOKEN_URL 업데이트:

 FB_AUTHORIZATION_BASE_URL = "https://www.facebook.com/dialog/oauth" FB_TOKEN_URL = "https://graph.facebook.com/oauth/access_token"

홈페이지:

 @app.route("/") def index(): return """ <a href="/fb-login">Login with Facebook</a> """

3단계: 로그인 및 콜백 엔드포인트

앱이 ngrok http 5000 명령을 사용하여 ngrok 뒤에서 제공되는 경우 현재 URL을 ngrok URL로 설정해야 합니다.

 # Your ngrok url, obtained after running "ngrok http 5000" URL = "https://abcdefgh.ngrok.io"

Facebook 로그인/설정, 유효한 OAuth 리디렉션 URI 설정에 URL을 추가해야 합니다.

유효한 OAuth 리디렉션 URI

사용자 이메일에 액세스하려면 scopeemail 을 추가해야 합니다.

 FB_SCOPE = ["email"] @app.route("/fb-login") def login(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, redirect_uri=URL + "/fb-callback", scope=FB_SCOPE ) authorization_url, _ = facebook.authorization_url(FB_AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url)

Facebook은 규정 준수 수정을 요구하므로 callback 경로는 약간 더 복잡합니다.

 from requests_oauthlib.compliance_fixes import facebook_compliance_fix @app.route("/fb-callback") def callback(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, scope=FB_SCOPE, redirect_uri=URL + "/fb-callback" ) # we need to apply a fix for Facebook here facebook = facebook_compliance_fix(facebook) facebook.fetch_token( FB_TOKEN_URL, client_secret=FB_CLIENT_SECRET, authorization_response=flask.request.url, ) # Fetch a protected resource, ie user profile, via Graph API facebook_user_data = facebook.get( "https://graph.facebook.com/me?fields=id,name,email,picture{url}" ).json() email = facebook_user_data["email"] name = facebook_user_data["name"] picture_url = facebook_user_data.get("picture", {}).get("data", {}).get("url") return f""" User information: <br> Name: {name} <br> Email: {email} <br> Avatar <img src="{picture_url}"> <br> <a href="/">Home</a> """

이제 Facebook으로 로그인을 클릭하면 전체 흐름을 진행할 수 있습니다.

Facebook 프로세스로 로그인

전체 코드는 facebook.py에 있습니다.

결론

축하합니다. SSO 로그인을 Flask 앱에 성공적으로 통합했습니다!

단순성을 위해 이 자습서에서는 사이트 간 요청 위조 공격을 방어하는 데 중요한 범위 및 상태와 같은 다른 OAuth 개념을 언급하지 않습니다. 또한 이 문서에서 다루지 않는 데이터베이스에 사용자 정보를 저장해야 할 수도 있습니다.

또한 앱은 프로덕션 시 https에서 제공되어야 하며, 이는 오늘날 Let's Encrypt를 사용하여 매우 쉽게 수행할 수 있습니다.

행복한 OAuthing!