实现OAuth2第三方认证(Node.js)
实现背景:
本人现在在开发一套多租的Saas平台。在开发运营中,很多租户都有一个共同的需求,他们都想把他们的数据同步到我们平台,以此来实时同步用户数据,方便他们使用
由于有了第三方数据同步的这么一个痛点需求,我们排期后决定实现。但想要同步数据就必须要客户提供他们的第三方接口
在本月有一家租户想进行数据同步,给我们提供了接口文档,接口需要OAuth鉴权
而在之前的租户的同步流程中,租户的第三方接口并没有使用OAuth2这么一种官方的流程化认证模式
所以在了解学习并开发完成后输出一篇文章记录一下
OAuth2简要介绍:
OAuth 2.0 是目前最流行的授权机制,专门用来授权第三方应用,获取第三方用户数据
OAuth 2.0共有4种授权模式:
-
授权码模式(authorization-code)
(1)根据官方提供的appid获取授权code
(2)根据appsecret、code请求获取access_token
(3)根据access_token请求用户数据
该模式对于其余三种在安全与兼容性方面相对来说比较完美,所以现在除了内部应用可能会使用第四种模式之外,大部分都是使用的授权码模式

官方图解(图源来自RFC 6749):
名词解释:
(1)Client:请求客户端,一般指本地
(2)Resource Owner:第三方数据资源提供者
(3)Access Token:鉴权令牌
(5)Authorization server:鉴权服务器,根据客户端请求处理发放鉴权令牌(Access Token)。
(6)Resource server:资源服务器,第三方接口数据返回的服务器。

-
简化模式(implicit)
简化模式较之授权码模式少了获取授权码(code)的中间步骤,故此模式适用的业务场景主要为前端应用,将access_token存储在前端,不涉及后端流程,安全性一般,使用也不广泛。 -
密码模式(password)
该模式顾名思义,使用用户名与密码请求令牌。这种模式的弊端也比较明显,在流程中需要直接传入用户名和密码请求令牌。
因此对于用户名和密码暴露的直接鉴权方式,如果在不是用户高度信任的第三方客户端中使用该鉴权模式会存在比较大的安全风险。 -
客户端凭证模式(client credentials)
该模式的鉴权由客户端发出,适用于完全信任的第三方应用(内部应用之间认证)。
打个比方大家应该就明白了
我们登录腾讯某个游戏,英雄联盟手游、王者荣耀等,他们的微信、QQ授权登录就是这一种模式
流程实现:
由于我们这边的技术栈是JS,故该流程将使用Node进行实现
明确认证接口配置
根据客户官方的接口文档,我们需要使用OAuth2.0授权码模式进行认证拉取客户数据
首先明确客户第三方接口参数(appid、appsecret)、请求地址等

接下来贴下部分示范代码于注释
编写OAuth鉴权流程公共类
// 引入公共配置... import ... from ...
export class oAuthHandle {
constructor(reqParam, oAuthType) {
// 组装请求头、OAuth参数等配置
this.clientParam = {
client_id: reqParam.client_id,
client_secret: reqParam.client_secret
}
this.option = {
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
}
this.oAuthType = oAuthType // OAuth鉴权类型,在此为授权码模式(authorization_code)
}
async requestOAuth(authorizeUrl,getAccessTokenUrl) {
let access_token = ''
switch (this.oAuthType) { // 区分OAuth2四种鉴权流程模式
case OAuthType.authorization_code: { // 授权码模式,此为工程配置,需自行根据情况引入配置
const authorizeCode = await this.getAuthorizeCode(authorizeUrl) // 请求code
access_token = this.getAccessToken(authorizeCode,getAccessTokenUrl) // 获取令牌
break;
}
}
return access_token
}
// 通过appid请求获取授权码code
async getAuthorizeCode(url) {
// 参数需根据实际接口配置,在此仅作示例
const option = {...this.option,
params:{client_id: this.clientParam.client_id,
response_type: 'code'},
content:`?response_type=code&client_id=${this.clientParam.client_id}`}
const result = await new Promise(resolve => {
// 请求地址,该片段需自行根据实际封装http请求,在此仅作示例,
const rs = HTTP.call('POST', url, option) || {};
resolve(rs.data)
}) || {};
// 根据实际数据结构返回数据
return result.data && result.data.code
}
// 通过app_secret、code请求获取access_token令牌
async getAccessToken(code,url) {
// 参数需根据实际接口配置,在此仅作示例
const option = {...this.option,
params:{
client_id: this.clientParam.client_id,
client_secret: this.clientParam.client_secret,
grant_type: OAuthType.authorization_code, // 配置类型,如果接口参数不同则需自定义配置
code: code,
redirect_uri: 'https://wx-gx.meix.com/institute_gx/management/content' // 遵循德邦接口规范
},
content: `?client_id=${this.clientParam.client_id}&client_secret=${this.clientParam.client_secret}&grant_type=authorization_code&code=${code}&redirect_uri=https://wx-gx.meix.com/institute_gx/management/content`
}
const result = await new Promise(resolve => {
// 请求地址,该片段需自行根据实际封装http请求,在此仅作示例,
const rs = HTTP.call('POST', url, option) || {};
resolve(rs.data)
}) || {};
// 根据实际数据结构返回数据
return result.data && result.data.access_token
}
}
调用公共类
// 参数需根据实际接口配置,在此仅作示例
const reqParams = {
authorizeParam:{
respond_type: 'code',
},
AccessTokenParam:{
grant_type: 'authorization'
},
client_id: this.crmCfg.client_id,
client_secret: this.crmCfg.client_secret,
}
const hostUrl = 'xxx' // 接口根路由地址
const oAuthAuthorizeUrl = 'xxx' // 请求授权码code地址
const getAccessTokenUrl = 'xxx' // 请求令牌地址
// 初始化OAuth2认证实例
const oAuth = new oAuthHandle(reqParams,OAuthType.authorization_code)
// 获取令牌
const access_token = await oAuth.requestOAuth(`${hostUrl}${oAuthAuthorizeUrl}`,`${hostUrl}${getAccessTokenUrl}`)
if (!access_token){
// 抛出异常
}
// ...请求接口数据
至此可返回access_token,可根据该令牌请求客户第三方接口数据
小结:
该文简要介绍了OAuth2.0四种认证方式以及优缺点,并实现了一个基于Node的授权码认证的代码示例
(全文完)
本文介绍了OAuth2.0授权码模式的原理及其在Node.js中的实现。通过示例代码展示了如何使用授权码模式获取第三方接口的access_token,用于数据同步。流程包括请求授权码、获取access_token和使用令牌请求数据。
579

被折叠的 条评论
为什么被折叠?



