作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Son Nguyen Kim's profile image

Son Nguyen Kim

孙正义精通软件工程和ML算法,总是努力用简单的方法解决问题.

Expertise

Previously At

Criteo
Share

应用程序通常需要登录功能,以便用户可以保存数据, create their own profiles, 或者只是为了限制对敏感资源的访问. In a modern app, 用户希望有标准的登录相关功能,如电子邮件验证, password reset, or multi-factor authentication. 这些功能虽然是必要的,但并不容易实现,通常也不是应用程序的主要业务.

On the user side, 他们可能不想经历冗长的注册过程,因为他们需要创建和记住另一个电子邮件和密码对. 没有合适的密码管理器, 用户倾向于重复使用相同的密码,这在安全性方面是可怕的.

单点登录(SSO),通常被用户称为 login with social media 按钮的发明就是为了解决这个问题. 对于用户来说,不用再经历另一个痛苦的注册过程是很容易的. 对于企业来说,消除用户的摩擦总是一个巨大的胜利 developers,所有与登录相关的功能现在都已安装 delegated 到身份提供者(Facebook, b谷歌,Twitter等).), meaning less code! Your app simply trusts 身份提供者执行其验证用户身份的工作.

SSO is usually powered by the OpenId 连接(OIDC)或SAML协议. SAML主要用于企业应用程序. OIDC建立在OAuth2之上,被Facebook、b谷歌等社交身份提供商使用. 在这篇文章中,我们将关注OIDC/OAuth2协议.

In this Flask login tutorial, 我们将编写一个循序渐进的指南,将SSO登录按钮添加到Flask应用程序中,使用SimpleLogin和Facebook作为身份提供者. 这可以在不使用任何外部库的情况下完成,但这是为了简化OAuth的复杂性, we’ll use Requests-OAuthlib,一个集成OAuth提供程序的库. 如果您对从头开始实现SSO感兴趣,请查看 实现SSO登录-原始方式.

在本文结束时,你应该有一个Flask应用程序,具有以下页面:

  • 设有登录按钮的网页
  • User information page where, upon successful login, 用户将能够看到诸如姓名之类的信息, email, and avatar

本教程的所有代码都可以在 flask-social-login-example库.

A demo is also available at here. Feel free to remix the code on Glitch.

Step 1: Bootstrap Flask App

Install flask and Requests-OAuthlib. You can also use virtualenv or pipenv to isolate the environment.

PIP安装flask requests_oauthlib

Create app.py 在主页上显示登录按钮的路由:

import flask

app = flask.Flask(__name__)

@app.route("/")
def index():
	return """
	Login
	"""

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

让我们运行这个应用程序并验证一切正常:

python app.py

当您打开http://localhost:5000时,应该会看到这个页面. The full code is on step1.py.

Login with SimpleLogin

步骤2:身份提供者凭证

目前有数百家(如果不是数千家的话)身份提供商,其中最受欢迎的是Facebook, Google, GitHub, and Instagram. For this post, SimpleLogin 是因为它对开发人员友好而选择的. 但是,相同的代码将适用于任何OAuth2身份提供程序. (免责声明:我恰好是SimpleLogin的联合创始人, 这可能是我决定使用它的一个因素.)

Please head to SimpleLogin 并创建一个帐户,如果你还没有一个,然后在开发者选项卡创建一个新的应用程序.

On the app detail page, 请复制您的AppID和AppSecret并将它们保存到变量环境中. 在OAuth术语中,客户端实际上是指第三方应用程序.e., your app. 我们可以将这些值直接放入代码中,但最好将凭据保存到环境变量中. 这也是第三个因素 The Twelve Factors.

OAuth2 Settings

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

In app.py请将这些行添加到文件的顶部以获得 client id and client 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 = "http://app . url ".simplelogin.io/oauth2/authorize"
TOKEN_URL = "http://app.simplelogin.io/oauth2/token"
USERINFO_URL = "http://app.simplelogin.io/oauth2/userinfo"

由于我们现在不想担心设置SSL,让我们告诉 Requests-OAuthlib 使用纯HTTP是可以的:

这允许我们使用普通的HTTP回调
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

与往常一样,这一步的代码是打开的 step2.py.

Step 3: Login Redirection

当用户点击登录按钮时:

  1. 用户将被重定向到身份登录提供商授权页面,询问用户是否希望与您的应用共享他们的信息.
  2. 在用户批准后,他们将被重定向到你的应用程序上的一个页面 code 在URL中,你的应用将使用这个URL来交换一个 access token 这允许您稍后从服务提供者获取用户信息.

We need therefore two routes: a login 路由,将用户重定向到标识提供者和 callback route that receives the code and exchanges it for access token. 回调路由还负责显示用户信息.

@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: 
Name: {user_info["name"]}
Email: {user_info["email"]}
Avatar
Home """

单击登录按钮将使您完成以下流程. The full code can be found on GitHub at step3.py.

使用simplellogin登录以允许用户信息

Login with Facebook

The setup of Facebook, Google, 和Twitter的登录有点复杂,需要额外的步骤,如设置SSL或选择正确的范围. 这些都超出了本文的讨论范围.

Apart from a sophisticated UI, 整合Facebook最困难的部分可能是找到一种方法在本地HTTPS上提供你的web应用,因为新版本的Facebook SDK不允许本地纯HTTP. I recommend using Ngrok,一个免费的工具,有一个快速的HTTPS URL.

Step 1: Create a Facebook App

Please head to http://developers.facebook.com and create a new app:

Create a New App ID

然后在下一个界面中选择“整合Facebook登录”:

Integrate Facebook Login

步骤2:Facebook OAuth凭证

点击左侧的“设置/基本”,复制 App ID and App Secret. They are actually OAuth client-id and client-secret.

Basic settings

Update the client-id and client-secret.

export FB_CLIENT_ID={您的facebook AppId}
export FB_CLIENT_SECRET={你的facebook AppSecret}

更新AUTHORIZATION_BASE_URL和TOKEN_URL:

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

The homepage:

@app.route("/")
def index():
	return """
	Login with Facebook
	"""

步骤3:登录和回调端点

If the app is served behind ngrok using ngrok http 5000 命令,我们需要将当前URL设置为ngrok URL.

运行“ngrok http 5000”后获得的ngrok url
URL = "http://abcdefgh.ngrok.io"

请确保将url添加到您的Facebook登录/设置,有效OAuth重定向uri设置:

Valid OAuth Redirect URIs

为了访问用户的电子邮件,您需要添加 email into scope:

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)

The callback route的情况要复杂一些,因为Facebook需要进行合规修复:

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, i.e. user profile, via Graph API

	facebook_user_data = facebook.get(
    	"http://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: 
Name: {name}
Email: {email}
Avatar
Home """

现在,当点击Login with Facebook,你应该能够通过整个流程.

Login with Facebook process

The full code is on facebook.py.

Conclusion

祝贺您——您已经成功地将SSO登录集成到Flask应用程序中!

为简单起见,本教程没有提到其他OAuth概念,例如 scope and state,这对于防御跨站点请求伪造攻击非常重要. 您可能还需要将用户信息存储在数据库中,这在本文中没有涉及.

该应用还需要在生产环境中用http提供服务,这在今天很容易做到 Let’s Encrypt.

Happy OAuthing!

Understanding the basics

  • 如何在Flask中创建登录页面?

    Flask中的登录页面基本上是一个HTML页面. 在Flask中处理登录的棘手部分可能是在会话中存储用户登录状态, 这通常是由烧瓶登录扩展处理. 这个扩展还附带了方便的login_required装饰器,限制对经过身份验证的用户的访问.

  • 单点登录是什么意思?

    单点登录使用户只需登录一次,就可以访问多个应用程序. 对于企业用户,这通常以应用程序门户的形式出现. 对于私人用户来说,最流行的单点登录形式可能是“登录Facebook”按钮.

  • 什么是单点登录,它是如何工作的?

    单点登录是一种将身份验证“委托”给称为“身份提供者”的另一方的系统.应用程序和身份提供者之间的通信通常由SAML协议(主要用于企业环境)或OIDC/OAuth2(主要用于消费者环境)处理。.

  • 单点登录的好处是什么?

    单点登录为用户和应用程序开发人员提供了双重优势. 用户不需要记住另一个密码,登录速度也很快. For developers, 他们不必实现与身份验证相关的功能,也不必担心存储用户电子邮件/密码的安全隐患.

  • Is OAuth single sign-on?

    OAuth是一种授权协议,它规定了应用程序如何访问用户资源. OIDC (OpenID Connect)是一种“身份验证”协议,是在OAuth之上创建的一层. OIDC和SAML通常是支持单点登录的协议.

  • How do you test SSO?

    您需要一个身份提供程序来测试SSO. 有成千上万的身份提供者,其中大多数都遵循OIDC. 对于不需要特定社交数据(Facebook feed)的应用程序, Twitter feed, etc), 使用SimpleLogin作为身份提供者可能是一个快速的解决方案,因为它“对开发人员友好”.”

  • Why is Flask used?

    Flask是Python中流行的web框架. With its expressiveness, 通常用Flask编写的代码可以很容易地翻译成其他语言和框架.

  • Why is Flask a microframework?

    微框架中的“微”意味着Flask只关注web,不包括数据库ORM之类的东西, cache management, or authentication. 这些特性作为扩展提供,可以根据您的需要启用.

就这一主题咨询作者或专家.
Schedule a call
Son Nguyen Kim's profile image
Son Nguyen Kim

Located in Paris, France

Member since June 17, 2015

About the author

孙正义精通软件工程和ML算法,总是努力用简单的方法解决问题.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

Expertise

Previously At

Criteo

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

世界级的文章,每周发一次.

订阅意味着同意我们的 privacy policy

Toptal Developers

Join the Toptal® community.