OAuth 2.0 是目前最流行的授权机制,用来授权第三方应用,获取用户数据。比如掘金这种第三方账号 微信、微博、github 登录方式一样。思考一下这种登录方式是如何设计和实现的呢?日常生活中很多APP或者网站在用户输入完手机号之后都需要发送验证码校验,那么这整套流程又是如何实现的呢?

一、OAuth的思路
OAuth在“客户端”和“服务供应商”之间,设置了一个授权层。“客户端”不能直接登录“服务供应商”,只能登录授权,以此将用户与客户端区分开来。“客户端”登录授权之后,“服务提供商”根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。

简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。
二、OAuth的登录实践
以GitHub为例子,实现OAuth的授权登录。接下来我会一步步实践如何在你的网站中接入github授权登录

1、GitHub 应用登记
点击按钮去github主页新建一个OAuth App,点击创建 按如下提示填写信息

2、代码实现
2.1 前端实现
前端采用了掘金的授权登录方式,当用户点击第三方GitHub登录,弹出一个新窗口
window.open("/oauth", "", "height=600, width=700")
在这个新窗口里只需要跳转链接,client_id,redirect_uri 就是之前创建的参数配置自己的就行。
window.location.href = 'github.com/login/oauth…' 用户授权登录之后会跳到redirect页面,在redirect请求后端带上刚产生的code,后端拿到code请求github得到的用户信息资料,最后关闭弹窗。
2.2 后端实现
后端作者采用的是Koa2,代码如下
router.get('/oauth', async function(ctx, next) {
const requestToken = ctx.request.query.code
const tokenResponse = await axios({
method: 'post',
url: 'https://github.com/login/oauth/access_token?' +
`client_id=${OAUTH_GITHUB.clientID}&` +
`client_secret=${OAUTH_GITHUB.clientSecret}&` +
`code=${requestToken}`,
headers: {
accept: 'application/json'
}
})
const accessToken = tokenResponse.data.access_token
const result = await axios({
method: 'get',
url: `https://api.github.com/user`,
headers: {
accept: 'application/json',
Authorization: `token ${accessToken}`
}
})
后面根据自己的业务需求,将获取到的信息存入到用户表中。这里的方式很多,我是直接将github授权登录的信息插入到我的用户表里,或者你新建一个第三方oauth表去存放也是可以的。
const oauthLogin = async (userData = {}) => {
const username = userData.username
const nickname = userData.username
const avatar = userData.avatar
const date = Date.now()
const userSql = `select * from users where username = '${username}' `
const rows = await exec(userSql)
if (rows.length > 0) {
return rows[0] || {}
} else {
const sql = `insert into users (username,password, nickname, avatar, date) values ('${username}', '${password}', '${nickname}', '${avatar}', '${date}');`
const insertData = await exec(sql)
}
}
最后的效果

三、短信验证登录
3.1 开通短信服务
短信验证自然需要用到服务商,阿里云有免费短信开通功能,免费开通短信服务,开通之后按每条0.04元计算。为了练习充了一元测试短信验证功能,免费开通这个还是非常的好的,不用发很多钱就可以上手测试

3.2 前端实现
还是拿掘金的案例来讲,用户点击注册输入手机号之后,点击获取验证码。


3.3后端实现
router.post('/sendSmsCodeToUser', async function (ctx, next) {
const { username } = ctx.request.body
CODE = Math.random().toString().slice(-6)
var client = new RPCClient({
accessKeyId: 'LTAI4FcGip5kqy1', // 自己申请短信的
accessKeySecret: 'BvmhpNobez41as1vA5z1QSbhTGIm',
endpoint: 'https://dysmsapi.aliyuncs.com',
apiVersion: '2019-12-14'
})
var params = {
"RegionId": "cn-hangzhou",
"PhoneNumbers": `${username}`,
"SignName": "起航网",
"TemplateCode": "SMS_180059442",
"TemplateParam": `{code: ${CODE}}`
}
var requestOption = {
method: 'POST'
}
var result = await client.request('SendSms', params, requestOption).then((res) => {
return res
}, (ex) => {
return ex
})
if ('Code' in result) {
ctx.body = new SuccessModel({message: '验证码发送成功'})
} else {
const limit = result.data.Message.split(':')[1]
ctx.body = limit >= 10 ? new ErrorModel({message: '同一手机号每天只能发送 10 条验证码'}) : new ErrorModel({message: '同一手机号每小时只能发送 5 条验证码'})
}
})
前后端请求对比CODE,实现短信验证登录功能