0%

2022-08-04 第三方登录之 GitHub OAuth 的接入与使用

2022-08-04 第三方登录之 GitHub OAuth 的接入与使用

文档:https://docs.github.com/cn/developers/apps/building-oauth-apps/creating-an-oauth-app

https://docs.github.com/cn/developers/apps/building-oauth-apps/authorizing-oauth-apps

最近研究了下第三方登录和 GitHub OAuth ,下面来记录一下 GitHub OAuth 的接入与使用

关于如何创建 OAuth 应用程序如何授权 OAuth 应用程序,其实 GitHub 官方文档里面已经说的很清楚了。

只不过,关于创建这一块,按文档的说明来还是比较清晰明了的,大部分人都会。但后面这一步,如何授权 OAuth 应用程序,就多少有点麻烦了,尤其是涉及OAuth 2.0的部分,看起来就更让人头大。故笔者也在此记录一下心得,总结下自己的使用感受和教训。

创建 OAuth 应用程序

首先是创建部分的坑,或者说心得。

image-20220804201039821

重定向 URL 中,官方已经指出,如果是线上的,则 重定向 URL 的主机和端口必须完全匹配回调 URL,重定向 URL 的路径必须引用回调 URL 的子目录,但如果是本地的,则 不需要匹配应用程序回调 url 中指定的端口

image-20220804201351375

所以在开发阶段,为了方便本地调试,可以把应用的“Authorization callback URL(授权回调 URL)”设置为本地 URL,避免重定向问题。

授权 OAuth 应用程序

接下来就是接入 GitHub OAuth 的关键了。

为了实现这个过程,我们需要一个前端和后端。

image-20220804202507500

在创建应用后,我们就可以拿到一个Client IDClient Secret,要注意的是, Client Secret只能放在后端,千万不能放在前端,是需要保密的,不能泄露。

随后,在前端就可以向 https://github.com/login/oauth/authorize 接口请求用户的 GitHub 身份。

image-20220804202726187

参考写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type GithubOauthAuthorizeData = {
/**
*
* 提供用于登录和授权应用程序的特定账户【可空】。注意,经过试验后,这里要填的是 GitHub 用户名,这样跳转之后会向用户建议登录该账号。
*/
login: string
state: string
redirect_uri: string
}
export function githubOauthAuthorize(data: GithubOauthAuthorizeData) {
const query = new URLSearchParams({
...data,
client_id: 'GITHUB_CLIENT_ID',
scope: '',
allow_signup: 'true',
})
const url = `https://github.com/login/oauth/authorize?${query.toString()}`
window.location.href = url // 直接跳转
// 或 window.open(url) // 或者另外开窗口
}

在前端合适的位置放置按钮,并绑定该函数。

image-20220804203451762

在这里需要重点说明下 redirect_uri(重定向 URL)

当用户接受请求,GitHub 将会重定向回该 URL,同时在 URL 的查询字符串中传入参数 codestate

例如:

1
http://localhost:3000/?code=xxxxxxxxxxxxxxxxxx&state=abcdefg

其中 code 就是我们需要的参数,有了这个就可以去申请 access_token,然后再去获取用户信息。

至于 state,是用来防止跨站请求伪造攻击的,只要校验下即可。

image-20220804204239389

这里也需要注意,拿到 code 之后不要在前端去申请 access_token,因为要申请 access_token需要用到 client_secret, 前面也说了,client_secret(客户端密钥)是不能泄露的,所以应该将 code 传给后端,由后端来继续后面的步骤。

接下来到了后端部分,参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import axios from 'axios'

type GithubAccessTokenData = {
client_id: string
client_secret: string
code: string
redirect_uri: string
}

type GithubAccessTokenResponse = {
access_token: string
scope: string
token_type: string
}

export async function getGithubAccessToken(data: GithubAccessTokenData): Promise<GithubAccessTokenResponse> {
return (await axios({
url: 'https://github.com/login/oauth/access_token',
method: 'POST',
headers: {
Accept: 'application/json',
},
data,
}))?.data

}

export async function getGithubUserInfo(token: string): Promise<any> {
return (await axios({
url: 'https://api.github.com/user',
method: 'GET',
headers: {
Authorization: `token ${token}`,
},
}))?.data
}

个人建议在申请 access_token 的时候配置 Acceptapplication/json,毕竟 json 格式对 js 来讲好处理很多,其他语言也类似。

image-20220804205145766

然后是根据access_token 去获取用户信息,返回的结果类似于这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"login" : "CaoMeiYouRen",
"id" : 123456,
"node_id" : "xxxxxxxxxxxxxxx",
"avatar_url" : "https://avatars.githubusercontent.com/u/40430746?v=4",
"gravatar_id" : "",
"url" : "https://api.github.com/users/CaoMeiYouRen",
"html_url" : "https://github.com/CaoMeiYouRen",
"followers_url" : "https://api.github.com/users/CaoMeiYouRen/followers",
"following_url" : "https://api.github.com/users/CaoMeiYouRen/following{/other_user}",
"gists_url" : "https://api.github.com/users/CaoMeiYouRen/gists{/gist_id}",
"starred_url" : "https://api.github.com/users/CaoMeiYouRen/starred{/owner}{/repo}",
"subscriptions_url" : "https://api.github.com/users/CaoMeiYouRen/subscriptions",
"organizations_url" : "https://api.github.com/users/CaoMeiYouRen/orgs",
"repos_url" : "https://api.github.com/users/CaoMeiYouRen/repos",
"events_url" : "https://api.github.com/users/CaoMeiYouRen/events{/privacy}",
"received_events_url" : "https://api.github.com/users/CaoMeiYouRen/received_events",
"type" : "User",
"site_admin" : false,
"name" : null,
"company" : null,
"blog" : "https://blog.cmyr.ltd/",
"location" : "中国",
"email" : null,
"hireable" : null,
"bio" : "主攻ts/js/vue,前端工程师,B站搜草梅友仁",
"twitter_username" : null,
"public_repos" : 198,
"public_gists" : 0,
"followers" : 17,
"following" : 5,
"created_at" : "2018-06-20T12:50:51Z",
"updated_at" : "2022-08-03T08:18:05Z"
}

然后跟本地的用户进行一个绑定即可,这里要注意的是,GitHub 用户的 id 是唯一的,用户名 login是可以修改的,所以应该跟 id建立关系。

到这一步就算完成了整个 GitHub OAuth 的对接,拿到用户数据之后要怎么做就是自己的事情了,看项目需求即可。

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/e53f109b.html
版权声明:转载请注明出处!

坚持原创技术分享,您的支持将鼓励我继续创作!