部署阿里云云函数舒畅无阻的请求 Github OpenApi 实现 OAuth2.0 登录
Opened this issue · 0 comments
在自己建站的过程中,想要实现登录功能其实并不是一个简单的活儿,它的主要难点不在于技术实现,而是难在独立开发者往往没有太多资金投入。
举个例子,如果我现在要实现一个手机号码短信登录,先不考虑用户意愿问题,我们需要购买的第一个第三方服务就是短信发送的服务,每发送一条短信验证码,都是真金白银的钱,为了防止被人恶意刷量,还要购买行为验证码(或风控相关的)服务,这背后要多少钱大家可以自行了解下。
换个思路,我们支持微信登录好了,结果一查要注册公司盖章提交审核,才能使用微信的第三方登录功能,还要每年交个 300 元。所以可选择的不多,Github OAuth 登录是我的首选项,因为大多数开发者都会有自己的 Github 账号,而 Github OAuth 登录又没有类似微信的各种限制。
不过问题是,Github 登录过程中要调用它的 OpenApi,如果你和我一样买的是大陆的云服务器,会经常超时,这非常令人头疼,修改 host 什么的根本卵用没有,买国外的服务器又死贵。不过好在阿里云的 FC(云函数)产品还是挺便宜的,接下来就介绍下如何利用云函数调用 OpenApi,而国内服务器又能调该云函数获取返回结果。
前提
因为我购买的是阿里云的 FC 产品,所以你最好也是和我一样,有一个阿里云账号,如果你还没购买,新用户可以试用三个月。
打开控制台
找到产品函数计算 FC,点击【管理控制台】。
进入之后,你会看到账号下的基础信息。
创建服务
找到左边菜单的【服务及函数】按钮,点击跳转后,将注意力移到最上方,地理位置选择美区(只要不是大陆地区就行),非常重要!
接着我们点击【创建服务】,名称随便填写,最好和我们要实现的功能相近。打开【高级选项】,我们要选择一个角色,没有的话,点下面创建一个就行。
创建函数
服务创建完成后,我们就可以开始创建云函数,点击【创建函数】。
选择【使用自定义运行时创建】,函数名称写一个比较贴近函数功能的名字,请求处理程序类型选择【处理 HTTP 请求】,运行环境推荐选比较稳定的 Node.js 16,代码上传方式我选择的是【使用示例代码】,这样我们可以知道如何写一个 Hello World 级别的云函数,并正确调用后慢慢实现我们的功能函数。
其它的选项我们都可以先使用默认的,点击底部【创建】按钮完成创建。
调用云函数
创建完成后,来到这一个选项卡【触发器管理(URL)】,就可以看到我们的访问地址了。
在选项卡【函数代码】中可以直接编写我们的接口,【测试函数】能够进行接口调用测试,都是很实用的,这里我们先打开【函数代码】看看写了啥。
可以看到我们的接口代码,使用 Apifox 调用下这个接口测试下。
返回正确,证明我们的云函数部署成功了。接下来就可以大施拳脚改造我们的请求接口,实现 Github Openapi 的调用了。
比如我主要是实现 OAuth2.0 登录,代码如下:
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios')
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(bodyParser.raw());
const port = 9000
app.get('/oauth/access_token', async (req, res) => {
let errorMsg
let tokenResponse = {}
try {
const { client_id, client_secret, code } = req.query
tokenResponse = await axios({
method: 'post',
url:
'https://github.com/login/oauth/access_token?' +
`client_id=${client_id}&` +
`client_secret=${client_secret}&` +
`code=${code}`,
timeout: 6000,
headers: {
accept: 'application/json',
},
})
} catch (error) {
errorMsg = error
}
res.send(errorMsg ? {
errorMsg
} : {
...tokenResponse.data
})
})
app.get('/oauth/user_info', async (req, res) => {
let errorMsg
let githubUserInfo = {}
try {
const { access_token } = req.query
githubUserInfo = await axios({
method: 'get',
url: 'https://api.github.com/user',
timeout: 6000,
headers: {
accept: 'application/json',
Authorization: `token ${access_token}`,
},
})
} catch (error) {
errorMsg = error
}
res.send(errorMsg ? {
errorMsg
} : {
...githubUserInfo.data
})
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
上面我写了两个接口,没在同一个接口实现两个接口的请求是因为会 401,但是分开就可以,这里非常奇怪,我也不知道是哪里问题,非常奇怪。
最后
现在你就可以在自己服务端去调这些你写好的接口了,比如我的调用如下:
async oauthGithubLogin(oauthGithubLoginDto: OAuthGithubLoginDto) {
const { code } = oauthGithubLoginDto
let tokenResponse: any = {}
let githubUserInfo: any = {}
try {
tokenResponse = await axios({
method: 'get',
url:
'https://github-auth-api-github-openapi-phktxmgeeb.us-east-1.fcapp.run/oauth/access_token?' +
`client_id=${OAUTH_GITHUB_CLIENT_ID}&` +
`client_secret=${OAUTH_GITHUB_CLIENT_SECRET}&` +
`code=${code}`,
timeout: 6000,
})
} catch (error) {
throw new RequestTimeoutException('Request github openapi timed out.')
}
try {
const { access_token: accessToken } = tokenResponse.data || {}
githubUserInfo = await axios({
method: 'get',
url: 'https://github-auth-api-github-openapi-phktxmgeeb.us-east-1.fcapp.run/oauth/user_info?' + `access_token=${accessToken}`,
timeout: 6000,
})
} catch (error) {
throw new RequestTimeoutException('Request github openapi timed out.')
}
console.log(githubUserInfo)
// 后续逻辑
}
好了,终于可以愉快调用 Github 的 OpenApi 了,整就一个舒畅。