在网页中接入 GitHub 帐号登录
在上一篇文章中,我简要地介绍了在网页中接入Google登录的方式,今天这篇文章再介绍一下接入GitHub登录的方式。同样是由于项目需要,所以学习了一番。 和 Google 相同的是,GitHub也是采用 OAuth 的方式授权。而不同点在于,Google 签发 JWT Token,而 GitHub 则是标准的 OAuth 认证过程。
OAuth 授权原理步骤
- 网站携带 ClientID 跳转到 GitHub 授权页面
- 用户授权后,GitHub 携带授权码重定向回到网站回调页面
- 网站通过授权码向 GitHub 请求用户令牌(Token)(验证授权码合法性)
- 网站通过用户令牌请求用户信息(或其它接口)
创建一个 OAuth App
OAuth 在 GitHub 中被叫作 OAuth Apps,所以需要先创建一个 OAuth App。
通过点击右上角头像的 Settings → Developer settings → OAuth Apps 进入到 OAuth Apps 创建和管理页面:https://github.com/settings/developers。
如下图所示,我已经创建了两个。第二个是用于我博客登录的。
点击右上角的“New OAuth App”进入新的 OAuth App 创建页面,需要填写的信息非常少。
题外话:GitHub 的页面风格看着比 Google 的真是要舒适多了。
注意最后一个回调地址(前/后端均可,取决你的实现),当用户点击授权后,GitHub 会携带**授权码(code)**回调/重定向到这个地址。
这个地址可以是任意合法的地址,比如http://localhost:8080/
,在本地开发调试的使用。
回调时,GitHub 会追加一个名为code
的查询参数到刚刚指定的回调地址中。(这个名为code
的参数是hardcode的,没有找到地方可以修改)比如:https://blog.twofei.com/login?type=github&code=xxxxxx
,注意后面的 code 部分。
另外,由于这是一个追加到 URL 中的查询参数,而且很明显是通过浏览器重定向回调的,所以这是一个 GET 请求,不是 POST。 我的博客最开始只支持 POST 登录,后来为了支持 GitHub,增加了 GET 方式登录。
由于 code 是通过 URL 传输的,为了更加安全起见:建议网站支持 HTTPS。(现在有完全免费的证书了,谁还不上 HTTPS 呢?)
创建好后,就可以拿到 Client ID 和对应的 Client Secret,同时还可以设置一个头像。Client ID 可以公开,Client Secret 请不要泄露。
前端添加GitHub登录代码
在自己网站的登录页面,加上一个GitHub登录的按钮,点击这个按钮后,跳转到GitHub授权页面供用户授权。 以下代码来自我博客和简单实现,仅供参考。
GitHub授权页面:https://github.com/login/oauth/authorize?client_id=你的ClientID。
<!-- 图片来自GitHub主页左上角的SVG -->
<svg id="github" height="32" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
<script>
var github = document.getElementById('github');
github.addEventListener('click', function() {
location.href = "https://github.com/login/oauth/authorize?client_id=你的ClientID";
});
</script>
在点击上面的图片按钮后,页面会转到GitHub授权页面:
点击绿色的授权按钮后,用户就会被重定向到注册 OAuth App 时的回调地址,参数中携带授权码code
。
后端通过授权码向GitHub请求用户令牌(Token)
前一篇文章在讲到后端处理 Google 的 JWT Token 的时候,后端会向 Google 验证拿到的 JWT 是否合法。在我们拿到 GitHub 的授权码的时候,同样需要向 GitHub 验证这个授权码是否合法,这个过程即是请求令牌的过程。
请求用户令牌(access_token)
令牌请求地址:POST https://github.com/login/oauth/access_token。
注意:这虽然是个 POST 请求,但是请求的参数是放在 URL 中的,不在 BODY 中。
有 3 个参数是必选的:
名字 | 含义 |
---|---|
client_id | 你的 ClientID |
client_secret | Client Secret |
code | 授权码 |
成功请求后,GitHub 会返回用户令牌(格式可以通过参数自定义,详见参数说明):
{"access_token":"e72e16c7e42f292c6912e7710c838347ae178b4a", "scope":"repo,gist", "token_type":"bearer"}
用令牌调用GitHub接口获取用户信息
拿到用户的令牌后,就可以做很多事了,今天我这篇文章只讲解获取用户信息。
用户信息接口地址:GET https://api.github.com/user。
在发请求时,需要携带用户令牌,这个令牌放在 HTTP 请求头部字段 Authorization
中。
虽然GitHub返回的是Bearer Token类型,但是API接口的要求的名字却是token
,见下。
GET https://api.github.com/user
Authorization: token 用户令牌
返回的信息如下:
{
"login": "movsb",
"id": 5374525,
"node_id": "MDQ6VXNlcjUzNzQ1MjU=",
"avatar_url": "https://avatars1.githubusercontent.com/u/5374525?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/movsb",
"html_url": "https://github.com/movsb",
"followers_url": "https://api.github.com/users/movsb/followers",
"following_url": "https://api.github.com/users/movsb/following{/other_user}",
"gists_url": "https://api.github.com/users/movsb/gists{/gist_id}",
"starred_url": "https://api.github.com/users/movsb/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/movsb/subscriptions",
"organizations_url": "https://api.github.com/users/movsb/orgs",
"repos_url": "https://api.github.com/users/movsb/repos",
"events_url": "https://api.github.com/users/movsb/events{/privacy}",
"received_events_url": "https://api.github.com/users/movsb/received_events",
"type": "User",
"site_admin": false,
"name": "桃子",
"company": "Shopee",
"blog": "https://blog.twofei.com",
"location": "Shenzhen, China",
"email": null,
"hireable": null,
"bio": null,
"public_repos": 46,
"public_gists": 1,
"followers": 108,
"following": 11,
"created_at": "2013-09-03T16:09:34Z",
"updated_at": "2019-07-21T13:32:02Z"
}
GitHub的登录名(login)是可变的,用户ID(id)不变。所以:如果这个ID没有与我们自己的用户系统绑定用户,则创建一个新用户绑定。否则,直接创建此用户的会话即可。