这是我的场景
-> 前端 React
-> 后端 节点
我正在使用 JWT 进行用户身份验证,即每次前端需要使用授权标头和不记名令牌请求后端的任何内容时。
我的疑问
我的网站上有一个用户 x,对于一个用例,我需要他将他的 github 帐户链接到他在我网站上已有的帐户。
为此,他单击链接 github 按钮并转到
https://github.com/login/oauth/authorize?client_id=xxxxxxx
,并授予共享其数据的权限,并重定向到在 github 上创建 oauth 应用程序时提供的回调链接。
我的服务器上的回调路由将收到一个代码,稍后可用于访问令牌,该令牌又可用于代表用户访问 GitHub 帐户。
但是疑问是我怎么知道这个github回调代码属于哪个用户呢?它属于用户x还是其他人?
在正常情况下,JWT可以帮助识别用户,但这里由于回调是从GitHub请求的,所以没有JWT令牌,因此没有机会识别用户!
我希望问题很清楚,提前感谢您的帮助!
作为 GitHub 中用户授权流程的一部分,您可以使用 state 参数发送任何随机数据以及启动 GitHub 授权流程的系统中的用户 ID。此状态参数应包含一个随机字符串以防止伪造攻击,并且可以包含任何其他任意数据(例如您的系统用户 ID),然后在您的应用程序中处理授权回调时,GitHub 将该 state 参数发送回您的应用。如果状态不匹配,则该请求是由第三方创建的,并且该过程应中止。
您可以在此处阅读有关 GitHub OAuth 应用程序如何工作的更多信息 另外,如果您想更多地了解作为 OAuth 2.0 授权框架规范一部分的状态参数,请在此处阅读更多相关信息
在您的后端,当您处理回调时,您现在在用户授权流程之后拥有从 GitHub 返回的访问令牌,通过它,您可以获取授权用户信息并将来自 GitHub 的用户 ID 与您的系统用户 ID 相关联您从状态参数获得的,这是一个示例代码:
查看实际实施示例 | 在 Fusebit 中运行 |
---|
import superagent from 'superagent';
// This code should be placed where you are handling the callback in your backend
// Put the access token from the callback response here
const access_token = '';
const userResponse = await superagent
.get('https://api.github.com/user')
.set('User-Agent', 'my-app')
.set('Authorization', `Bearer ${access_token}`)
.set('Accept', 'application/vnd.github.v3+json');
// Get the GitHub user id and connect it with the id you have in the state parameter
const gitHubUserId = userResponse.body.id;
回调响应正文将包含以下内容:
{
"access_token": "ghu_16C7e42F292c6912E7710c838347Ae178B4a",
"expires_in": 28800,
"refresh_token": "ghr_1B4a2e77838347a7E420ce178F2E7c6912E169246c34E1ccbF66C46812d16D5B1A9Dc86A1498",
"refresh_token_expires_in": 15811200,
"scope": "",
"token_type": "bearer"
}
用户响应将类似于:
{
"login": "octocat",
"id": 1,
"node_id": "MDQ6VXNlcjE=",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false,
"name": "monalisa octocat",
"company": "GitHub",
"blog": "https://github.com/blog",
"location": "San Francisco",
"email": "[email protected]",
"hireable": false,
"bio": "There once was...",
"twitter_username": "monatheoctocat",
"public_repos": 2,
"public_gists": 1,
"followers": 20,
"following": 0,
"created_at": "2008-01-14T04:33:35Z",
"updated_at": "2008-01-14T04:33:35Z",
"private_gists": 81,
"total_private_repos": 100,
"owned_private_repos": 100,
"disk_usage": 10000,
"collaborators": 8,
"two_factor_authentication": true,
"plan": {
"name": "Medium",
"space": 400,
"private_repos": 20,
"collaborators": 0
}
}
用户自己的浏览器从 Github 进行最终重定向,并将授权代码传递到您的客户端后端应用程序。
GitHub 从不直接联系您的客户。这一切都是通过用户浏览器完成的。
所以,这就是客户端知道代码属于谁的方式。此外,协议中的状态和 PKCE 安全功能进一步提高了安全性,只有发出初始请求的客户端应用程序与完成流程的客户端应用程序相同。
我最近在这里发表了有关状态和随机数参数的博客: