OAuth2 从头开始
你到处都能看到它:“使用<Google|Twitter|GitHub|Facebook|等>登录”。我个人非常喜欢它。它快捷、简单,还能节省我的时间。谁还需要记住那么多密码呢?哎呀,我就是用它来登录写这篇文章的。
现在是时候了解它的工作原理了。跟我一起,探索 OAuth 2 的神奇世界……
TLDR
OAuth 2 实现起来很简单。只需两步:请求验证码并使用该验证码获取令牌。就是这样。如果您更喜欢用其他语言阅读这篇文章,我已将其翻译成 TypeScript 版本。
设置客户端
我选择了 Google,但由于 OAuth 是一个标准,所以对于任何提供商来说,它都应该相当类似。以下是如何在 Google 上设置 OAuth 客户端:
- 在 Google 信息中心上创建新项目
- 为该项目启用 API。您可以启用 Google 的任何服务:云端硬盘、Gmail、表格、文档、语音转文字等。您需要的基本 API 是 Google People API,它提供有关用户个人资料的信息
- 创建一个 OAuth 客户端。这将是您请求 OAuth 令牌所需的客户端 ID/密钥。首先点击“创建凭据”,然后点击“OAuth 客户端 ID”。系统会提示您创建一个同意屏幕。按照提示操作,然后像这样填写表单。确保设置授权域名和重定向域名。我使用的是
https://localhost
,但您可以使用任何您喜欢的,只要它是 HTTPS 协议即可。使用此 Node 包 ,在本地运行 HTTPS 协议非常容易。 - 复制客户端 ID 和密钥以供稍后使用。
获取代币
现在到了最有趣的部分。只需两步即可从 Google 获取 OAuth 令牌:
请求授权码
该代码不是令牌,它被称为授权码,用于稍后获取令牌。
“这太蠢了。为什么不直接发送令牌呢?”问得好。以前就是这样的。它被称为隐式授权类型。这是一个糟糕的主意,通常不再推荐使用(在某些情况下甚至被彻底禁止)。
我们将使用授权码授权类型。它需要多一步,但更安全。
// GET request with the following params
{
code_challenge_method: 'S256',
scope: 'email profile', // tells google what info you want
access_type: 'offline',
response_type: 'code',
client_id: clientId, // clientID from step 1
redirect_uri: redirectUri, // page that handles token request
code_challenge: challengeToken, // hashed/encoded PKCE challenge
state: stateString, // random guid that will be passed back to you
}
// example
<a href="https://accounts.google.com/o/oauth2/v2/auth?code_challenge_method=S256&scope=email%20profile&access_type=offline&response_type=code&client_id=<client id>&redirect_uri=https://localhost/auth&code_challenge=o259Sjip6Cevgfe8RUw59jVO5z1mSzji_OuzIZFDTug&state=434595.10145617445">
Login with Google
</a>
上述code_challenge
参数来自一个名为PKCE的方法。它代表代码交换的证明密钥 (Proof Key for Code Exchange),是一种帮助提高 OAuth 安全性的安全方法。其核心是一个经过哈希处理的字符串,您将其发送给服务提供者,以便服务提供者在第二步中通过发送经过哈希处理的原始字符串来验证您的身份。有一个非常有用的Node 包可以帮助您生成 PKCE 挑战。
请求 OAuth 令牌
如果第一个请求一切顺利,服务商将要求用户登录,生成授权码,并重定向到redirect_uri
参数中指定的 URI。它将包含两个重要的 URL 参数:code
和state
。
Code 是请求 OAuth 令牌所需的授权码。
状态是您在上一步中发送的初始state
参数。这是一种简单的机制,用于确保客户端能够验证服务器的身份。如果状态不匹配或未包含,则表明您不应信任该请求。
// POST request with the following params
{
code: authCode, // authorization code from the provider
client_id: clientId, // id of the OAuth client
client_secret: clientSecret, // secret of the OAuth client
redirect_uri: redirectUri, // same from last request ¯\_(ツ)_/¯
grant_type: 'authorization_code',
code_verifier: codeVerifier, // raw PKCE token
}
// returns the following payload
{
access_token: <access token>, // this can be used to query APIs
refresh_token: <refresh token>, // can be used to get a new token
expires_in: <expiration in seconds>, // usually set to an hour
id_token: <id of the user>, // haven't really found a use for this
}
使用令牌!
然后,您可以使用令牌代表用户从 Google 获取数据。
axios.get(
'https://www.googleapis.com/oauth2/v2/userinfo',
{
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': `Bearer ${token}`
}
}
)
Google 有一个很酷的OAuth 游乐场,您可以在其中尝试各种 API。
就这样!你完成了!
资源
以下是我用来了解此问题的一些资源的链接:
PKCE 解释:https://oauth.net/2/pkce/
PKCE 节点包:https://www.npmjs.com/package/pkce-challenge
Google OAuth 游乐场:https://developers.google.com/oauthplayground
OAuth2 概述:https://aaronparecki.com/oauth-2-simplified/#web-server-apps
Google OAuth 演练:https://developers.google.com/identity/protocols/OAuth2InstalledApp#obtainingaccesstokens
示例 GitHub 仓库:https://github.com/coleHafner/oauth-test/tree/parcel
文章来源:https://dev.to/colehafner/oauth2-from-scratch-11ij