bjx-auth 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,216 @@
1
+ const { passportapi } = require('./axios')
2
+ const { getReqBody } = require('./sign')
3
+
4
+ //https://passportapi.bjx.com.cn/swagger/swagger-ui/index.html#/
5
+
6
+ /**
7
+ * nodejs授权
8
+ */
9
+ async function token(opts, signObj = {}) {
10
+ opts.data = await getReqBody(null, false, signObj)
11
+ return passportapi({
12
+ url: '/api/v1/token/web',
13
+ method: 'POST',
14
+ ...opts,
15
+ })
16
+ }
17
+
18
+ async function tokenRefresh(opts, signObj = {}) {
19
+ opts.data = await getReqBody(null, false, signObj)
20
+ return passportapi({
21
+ url: '/api/v1/token/refresh/web',
22
+ method: 'POST',
23
+ ...opts,
24
+ })
25
+ }
26
+
27
+ async function getToken(opts, signObj) {
28
+ if (opts.__isRefresh__) {
29
+ return tokenRefresh(opts, signObj)
30
+ } else {
31
+ return token(opts, signObj)
32
+ }
33
+ }
34
+
35
+ /**
36
+ * 其他接口
37
+ */
38
+ // 短信登录
39
+ async function loginSms(opts, signObj = {}) {
40
+ opts.data = await getReqBody(opts.data, true, signObj)
41
+ return passportapi({
42
+ url: '/api/v1/login/sms/web',
43
+ method: 'POST',
44
+ ...opts,
45
+ })
46
+ }
47
+
48
+ // 密码登录
49
+ async function loginPwd(opts, signObj = {}) {
50
+ opts.data = await getReqBody(opts.data, true, signObj)
51
+ return passportapi({
52
+ url: '/api/v1/login/pwd/web',
53
+ method: 'POST',
54
+ ...opts,
55
+ })
56
+ }
57
+
58
+ // 短信注册
59
+ async function registerSms(opts, signObj = {}) {
60
+ opts.data = await getReqBody(opts.data, true, signObj)
61
+ return passportapi({
62
+ url: '/api/v1/register/sms/web',
63
+ method: 'POST',
64
+ ...opts,
65
+ })
66
+ }
67
+
68
+ // 账户登出 (set-cookie + 返回clear_cache回调地址)
69
+ async function logout(opts, signObj = {}) {
70
+ opts.data = await getReqBody(null, false, signObj)
71
+ return passportapi({
72
+ url: '/api/v1/logout/web',
73
+ method: 'POST',
74
+ ...opts,
75
+ })
76
+ }
77
+
78
+ // 快速登录/注册
79
+ async function loginSmsQuick(opts, signObj = {}) {
80
+ opts.data = await getReqBody(opts.data, true, signObj)
81
+ return passportapi({
82
+ url: '/api/v1/login/sms/quick/web',
83
+ method: 'POST',
84
+ ...opts,
85
+ })
86
+ }
87
+
88
+ // 设置用户身份
89
+ async function userBusmold(opts, signObj = {}) {
90
+ opts.data = await getReqBody(opts.data, false, signObj)
91
+ return passportapi({
92
+ url: '/api/v1/user/busmold/seekers/set',
93
+ method: 'POST',
94
+ ...opts,
95
+ })
96
+ }
97
+
98
+ // 根据手机号判断用户是否存在
99
+ async function userExist(opts, signObj = {}) {
100
+ opts.data = await getReqBody(opts.data, false, signObj)
101
+ return passportapi({
102
+ url: '/api/v1/user/exist/phone',
103
+ method: 'POST',
104
+ ...opts,
105
+ })
106
+ }
107
+
108
+ // 找回密码前验证码
109
+ async function pwdResetVerify(opts, signObj = {}) {
110
+ opts.data = await getReqBody(opts.data, true, signObj)
111
+ return passportapi({
112
+ url: '/api/v1/user/pwd/reset/verify',
113
+ method: 'POST',
114
+ ...opts,
115
+ })
116
+ }
117
+
118
+ // 找回密码
119
+ async function pwdReset(opts, signObj = {}) {
120
+ opts.data = await getReqBody(opts.data, true, signObj)
121
+ return passportapi({
122
+ url: '/api/v1/user/pwd/reset',
123
+ method: 'POST',
124
+ ...opts,
125
+ })
126
+ }
127
+
128
+ // 获取公众号二维码
129
+ async function wxpubCode(opts, signObj = {}) {
130
+ opts.data = await getReqBody(opts.data, false, signObj)
131
+ return passportapi({
132
+ url: '/api/v1/wechat/wxpub/qrcode',
133
+ method: 'POST',
134
+ ...opts,
135
+ })
136
+ }
137
+
138
+ // 公众号扫码登录
139
+ async function wxpubScan(opts, signObj = {}) {
140
+ opts.data = await getReqBody(opts.data, false, signObj)
141
+ return passportapi({
142
+ url: '/api/v1/wechat/wxpub/scan/login',
143
+ method: 'POST',
144
+ ...opts,
145
+ })
146
+ }
147
+
148
+ // 公众号登录后绑定
149
+ async function wxpubBindLogin(opts, signObj = {}) {
150
+ opts.data = await getReqBody(opts.data, true, signObj)
151
+ return passportapi({
152
+ url: '/api/v1/wechat/wxpub/scan/bindlogin',
153
+ method: 'POST',
154
+ ...opts,
155
+ })
156
+ }
157
+
158
+ async function wxpubH5Code(opts, signObj = {}) {
159
+ opts.data = await getReqBody(opts.data, false, signObj)
160
+ return passportapi({
161
+ url: '/api/v1/wechat/wxpub/h5/getcode',
162
+ method: 'POST',
163
+ ...opts,
164
+ })
165
+ }
166
+
167
+ async function wxpubH5BindLogin(opts, signObj = {}) {
168
+ opts.data = await getReqBody(opts.data, true, signObj)
169
+ return passportapi({
170
+ url: '/api/v1/wechat/wxpub/h5/bindlogin',
171
+ method: 'POST',
172
+ ...opts,
173
+ })
174
+ }
175
+
176
+ async function webappCode(opts, signObj = {}) {
177
+ opts.data = await getReqBody(opts.data, false, signObj)
178
+ return passportapi({
179
+ url: '/api/v1/wechat/webapp/code',
180
+ method: 'POST',
181
+ ...opts,
182
+ })
183
+ }
184
+
185
+ async function webappBindLogin(opts, signObj = {}) {
186
+ opts.data = await getReqBody(opts.data, true, signObj)
187
+ return passportapi({
188
+ url: '/api/v1/wechat/webapp/bindlogin',
189
+ method: 'POST',
190
+ ...opts,
191
+ })
192
+ }
193
+
194
+ exports = module.exports = {
195
+ getToken,
196
+ loginSms,
197
+ loginPwd,
198
+ registerSms,
199
+ logout,
200
+
201
+ loginSmsQuick,
202
+ userBusmold,
203
+ userExist,
204
+ pwdResetVerify,
205
+ pwdReset,
206
+
207
+ wxpubCode,
208
+ wxpubScan,
209
+ wxpubBindLogin,
210
+
211
+ wxpubH5Code,
212
+ wxpubH5BindLogin,
213
+
214
+ webappCode,
215
+ webappBindLogin,
216
+ }
@@ -0,0 +1,7 @@
1
+ let hashImpl
2
+ if (process.env.USE_ENV === 'web') {
3
+ hashImpl = require('./web')
4
+ } else {
5
+ hashImpl = require('./node')
6
+ }
7
+ module.exports = hashImpl
@@ -0,0 +1,31 @@
1
+ const crypto = require('crypto')
2
+
3
+ function encryptRSA(str, publicPem) {
4
+ if (!publicPem) throw new Error('publicPem is required')
5
+ const dataBuffer = Buffer.from(str, 'utf8')
6
+ const encrypted = crypto.publicEncrypt(
7
+ {
8
+ key: publicPem,
9
+ padding: crypto.constants.RSA_PKCS1_PADDING,
10
+ },
11
+ dataBuffer,
12
+ )
13
+ return encrypted.toString('base64')
14
+ }
15
+
16
+ function encryptAES(str) {
17
+ const iv = crypto.randomBytes(16) // 密匙和IV一致
18
+ const key = iv
19
+ const cipher = crypto.createCipheriv('aes-128-cbc', key, iv)
20
+ let encrypted = cipher.update(str, 'utf8', 'base64')
21
+ encrypted += cipher.final('base64')
22
+ return {
23
+ iv: iv.toString('hex'),
24
+ encrypted,
25
+ }
26
+ }
27
+
28
+ exports = module.exports = {
29
+ encryptRSA,
30
+ encryptAES,
31
+ }
@@ -0,0 +1,31 @@
1
+ const JSEncrypt = require('jsencrypt')
2
+
3
+ const AES = require('crypto-js/aes')
4
+ const WordArray = require('crypto-js/lib-typedarrays')
5
+ const Pkcs7 = require('crypto-js/pad-pkcs7')
6
+ const Hex = require('crypto-js/enc-hex')
7
+
8
+ function encryptRSA(str, publicPem) {
9
+ if (!publicPem) throw new Error('publicPem is required')
10
+ const encryptor = new JSEncrypt()
11
+ encryptor.setPublicKey(publicPem)
12
+ const encrypted = encryptor.encrypt(str)
13
+ return encrypted
14
+ }
15
+ function encryptAES(str) {
16
+ const iv = WordArray.random(16) // 密匙和IV一致
17
+ const key = iv
18
+ const encrypted = AES.encrypt(str, key, {
19
+ iv,
20
+ padding: Pkcs7,
21
+ })
22
+ return {
23
+ iv: iv.toString(Hex),
24
+ encrypted: encrypted.toString(),
25
+ }
26
+ }
27
+
28
+ exports = module.exports = {
29
+ encryptRSA,
30
+ encryptAES,
31
+ }
@@ -0,0 +1,7 @@
1
+ let hashImpl
2
+ if (process.env.USE_ENV === 'web') {
3
+ hashImpl = require('./web')
4
+ } else {
5
+ hashImpl = require('./node')
6
+ }
7
+ module.exports = hashImpl
@@ -0,0 +1,14 @@
1
+ const crypto = require('crypto')
2
+
3
+ function hashHS256(str, key) {
4
+ return crypto.createHmac('sha256', key).update(str).digest('base64')
5
+ }
6
+
7
+ function hashMD5(str) {
8
+ return crypto.createHash('md5').update(str).digest('hex').toUpperCase()
9
+ }
10
+
11
+ exports = module.exports = {
12
+ hashHS256,
13
+ hashMD5,
14
+ }
@@ -0,0 +1,18 @@
1
+ const HmacSHA256 = require('crypto-js/hmac-sha256')
2
+ const Base64 = require('crypto-js/enc-base64')
3
+
4
+ const MD5 = require('crypto-js/md5')
5
+ const Hex = require('crypto-js/enc-hex')
6
+
7
+ function hashHS256(str, key) {
8
+ return HmacSHA256(str, key).toString(Base64)
9
+ }
10
+
11
+ function hashMD5(str) {
12
+ return MD5(str).toString(Hex)
13
+ }
14
+
15
+ exports = module.exports = {
16
+ hashHS256,
17
+ hashMD5,
18
+ }
@@ -0,0 +1,59 @@
1
+ const reqSign = require('./reqSign')
2
+ const reqEncrypt = require('./reqEncrypt')
3
+ const reqSginOld = require('./reqSginOld')
4
+
5
+ async function getReqBody(data, isEncrypt, opts) {
6
+ let {
7
+ eqp = '',
8
+ os = '',
9
+ ba = '',
10
+ bp = '',
11
+ ver = '',
12
+ apiVersion = '',
13
+ signVersion = '',
14
+ clientId = '',
15
+ clientSecret = '',
16
+ ctx,
17
+ } = opts || {}
18
+ if (ctx) {
19
+ if (!eqp) {
20
+ eqp = ctx.uuid
21
+ }
22
+ if (!os) {
23
+ eqp = ctx.isMobi ? 2 : 1
24
+ }
25
+ if (!ba) {
26
+ ba = ctx.query.ba
27
+ }
28
+ if (!bp) {
29
+ bp = ctx.query.bp
30
+ }
31
+ }
32
+
33
+ const obj = {
34
+ eqp,
35
+ os,
36
+ ba,
37
+ bp,
38
+ ver,
39
+ apiVersion,
40
+ signVersion,
41
+ clientId,
42
+ clientSecret,
43
+ }
44
+
45
+ if (isEncrypt && data && Object.keys(data).length > 0) {
46
+ obj.data = await reqEncrypt(data)
47
+ } else {
48
+ obj.data = data || {}
49
+ }
50
+
51
+ return reqSign(obj)
52
+ }
53
+
54
+ exports = module.exports = {
55
+ reqSign,
56
+ reqEncrypt,
57
+ getReqBody,
58
+ ...reqSginOld,
59
+ }
@@ -0,0 +1,45 @@
1
+ const reqSign = require('./reqSign')
2
+ const { passportapi } = require('../axios')
3
+ const { errorLogger } = require('../../logger')
4
+
5
+ // 获取公钥
6
+ let publicPemCache = null
7
+ async function getPublicPem() {
8
+ if (publicPemCache && publicPemCache.expiresAt > Date.now()) {
9
+ return publicPemCache.value
10
+ }
11
+ let body = reqSign()
12
+ try {
13
+ const { data } = await passportapi({
14
+ url: '/api/v1/common/config/security',
15
+ method: 'POST',
16
+ data: body,
17
+ })
18
+
19
+ if (data.isError === false) {
20
+ publicPemCache = {
21
+ value: `-----BEGIN PUBLIC KEY-----\n${data.data.rsaPubkey}\n-----END PUBLIC KEY-----`,
22
+ expiresAt: Date.now() + 8 * 3600 * 1000,
23
+ }
24
+ return publicPemCache.value
25
+ } else {
26
+ throw new Error(data.error)
27
+ }
28
+ } catch (error) {
29
+ errorLogger(error)
30
+ }
31
+ }
32
+
33
+ function clearPublicPemCache() {
34
+ publicPemCache = null
35
+ }
36
+
37
+ function hasPublicPemCache() {
38
+ return !!publicPemCache
39
+ }
40
+
41
+ exports = module.exports = {
42
+ getPublicPem,
43
+ clearPublicPemCache,
44
+ hasPublicPemCache,
45
+ }
@@ -0,0 +1,16 @@
1
+ const { getPublicPem } = require('./publicPem')
2
+ const { encryptRSA, encryptAES } = require('./encrypt')
3
+
4
+ async function getReqEncrypt(data) {
5
+ if (!data) throw new Error('data is required')
6
+ const publicPem = await getPublicPem()
7
+ const dataStr = JSON.stringify(data)
8
+ const { encrypted, iv } = encryptAES(dataStr)
9
+ const encryptedIv = encryptRSA(iv, publicPem)
10
+ return {
11
+ akaParams: encrypted,
12
+ secretKey: encryptedIv,
13
+ }
14
+ }
15
+
16
+ exports = module.exports = getReqEncrypt
@@ -0,0 +1,89 @@
1
+ const { hashMD5 } = require('./hash')
2
+ const config = require('../../config')
3
+
4
+ function getReqSign(params, ...moreParams) {
5
+ if (typeof params === 'string') {
6
+ params = {
7
+ EQP: params || '',
8
+ OS: moreParams[0] || '',
9
+ BA: moreParams[1] || '',
10
+ BP: moreParams[2] || '',
11
+ }
12
+ }
13
+ let { EQP, OS, BA, BP, Ver, ctx } = params || {}
14
+ if (ctx) {
15
+ if (!EQP) {
16
+ EQP = ctx.uuid
17
+ }
18
+ if (!OS) {
19
+ OS = ctx.isMobi ? 2 : 1
20
+ }
21
+ if (!BA) {
22
+ BA = ctx.query.ba
23
+ }
24
+ if (!BP) {
25
+ BP = ctx.query.bp
26
+ }
27
+ }
28
+
29
+ const obj = {
30
+ EQP: EQP || config.eqp || '',
31
+ OS: OS || config.os * 1 || 1,
32
+ BA: BA || config.ba || '',
33
+ BP: BP || config.bp || '',
34
+ Ver: Ver || config.ver || '1.0.0',
35
+ TS: Date.now(),
36
+ }
37
+
38
+ const secret = 'bjxstat2019'
39
+ const signStr = `EQP=${obj.EQP}&OS=${obj.OS}&BA=${obj.BA}&BP=${obj.BP}&Ver=${obj.Ver}&TS=${obj.TS}+${secret}`
40
+ const Sign = hashMD5(signStr).toUpperCase()
41
+ return Object.assign(obj, { Sign })
42
+ }
43
+
44
+ function getReqSign2(params, ...moreParams) {
45
+ if (typeof params === 'string') {
46
+ params = {
47
+ EQP: params || '',
48
+ OS: moreParams[0] || '',
49
+ BA: moreParams[1] || '',
50
+ BP: moreParams[2] || '',
51
+ XAppId: moreParams[3] || '',
52
+ }
53
+ }
54
+ let { EQP, OS, BA, BP, Ver, XAppId, ctx } = params || {}
55
+ if (ctx) {
56
+ if (!EQP) {
57
+ EQP = ctx.uuid
58
+ }
59
+ if (!OS) {
60
+ OS = ctx.isMobi ? 2 : 1
61
+ }
62
+ if (!BA) {
63
+ BA = ctx.query.ba
64
+ }
65
+ if (!BP) {
66
+ BP = ctx.query.bp
67
+ }
68
+ }
69
+
70
+ const obj = {
71
+ EQP: EQP || config.eqp || '',
72
+ OS: OS || config.os * 1 || 1,
73
+ BA: BA || config.ba || '',
74
+ BP: BP || config.bp || '',
75
+ Ver: Ver || config.ver || '1.0.0',
76
+ TS: Date.now(),
77
+ XAppId: XAppId || config.clientId || '',
78
+ }
79
+
80
+ const secret = '%SiGn2021!@#'
81
+ const signStr = `EQP=${obj.EQP}&OS=${obj.OS}&BA=${obj.BA}&BP=${obj.BP}&Ver=${obj.Ver}&TS=${obj.TS}&XAppId=${obj.XAppId}+${secret}`
82
+ const Sign = hashMD5(signStr).toUpperCase()
83
+ return Object.assign(obj, { Sign })
84
+ }
85
+
86
+ exports = module.exports = {
87
+ getReqSign,
88
+ getReqSign2,
89
+ }
@@ -0,0 +1,80 @@
1
+ const { hashHS256 } = require('./hash')
2
+ const config = require('../../config')
3
+
4
+ // 请求签名相关
5
+ function sortData(data) {
6
+ if (Object.prototype.toString.call(data) === '[object Object]') {
7
+ return Object.keys(data)
8
+ .sort() // 默认情况下 sort 会按字典顺序(ASCII 顺序)进行排序
9
+ .reduce((newObj, key) => {
10
+ newObj[key] = sortData(data[key])
11
+ return newObj
12
+ }, {})
13
+ } else if (Object.prototype.toString.call(data) === '[object Array]') {
14
+ return data.map((item) => sortData(item))
15
+ } else {
16
+ return data
17
+ }
18
+ }
19
+ function objToStr(data) {
20
+ let dataArr = []
21
+ Object.entries(data).map(([key, value]) => {
22
+ if (value === undefined || value === '' || value === null) {
23
+ } else {
24
+ if (
25
+ Object.prototype.toString.call(value) === '[object Array]' ||
26
+ Object.prototype.toString.call(value) === '[object Object]'
27
+ ) {
28
+ dataArr.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`)
29
+ } else {
30
+ dataArr.push(`${key}=${encodeURIComponent(value)}`)
31
+ }
32
+ }
33
+ })
34
+ return dataArr.join('&')
35
+ }
36
+
37
+ function signFn(data, signKey) {
38
+ const sorted = sortData(data)
39
+ const dataStr = objToStr(sorted)
40
+ const sign = hashHS256(dataStr, signKey)
41
+ return {
42
+ ...data,
43
+ sign,
44
+ }
45
+ }
46
+
47
+ function getReqSign(params, signKey) {
48
+ const {
49
+ eqp,
50
+ os,
51
+ ba,
52
+ bp,
53
+ ver,
54
+ apiVersion,
55
+ signVersion,
56
+ clientId,
57
+ clientSecret,
58
+ data = {},
59
+ } = params || {}
60
+
61
+ const obj = {
62
+ eqp: eqp || config.eqp || '',
63
+ os: os * 1 || config.os * 1 || 1,
64
+ ba: ba || config.ba || '',
65
+ bp: bp || config.bp || '',
66
+ ver: ver || config.ver || '1.0.0',
67
+ ts: Date.now(),
68
+ apiVersion: apiVersion || config.apiVersion || '1.0.0',
69
+ signVersion: signVersion || config.signVersion || 'V1',
70
+ clientId: clientId || config.clientId || '',
71
+ clientSecret: clientSecret || config.clientSecret || '',
72
+ data,
73
+ }
74
+ signKey = signKey || config.signKey
75
+
76
+ const res = signFn(obj, signKey)
77
+ return res
78
+ }
79
+
80
+ exports = module.exports = getReqSign
@@ -0,0 +1,72 @@
1
+ const { auth, enterpriseapi } = require('./axios')
2
+ const { getReqSign } = require('./sign')
3
+
4
+ /**
5
+ * nodejs授权
6
+ */
7
+ async function baseInfo(opts, signObj = {}) {
8
+ opts.data = { ...opts.data, ...getReqSign(signObj) }
9
+ return auth({
10
+ url: '/api/User/' + opts.__type__,
11
+ method: 'POST',
12
+ ...opts,
13
+ })
14
+ }
15
+
16
+ async function userInfo(opts, signObj = {}) {
17
+ opts.data = { ...opts.data, ...getReqSign(signObj) }
18
+ return enterpriseapi({
19
+ url: '/enterprise/user/userInfo',
20
+ method: 'POST',
21
+ ...opts,
22
+ }).then((res) => {
23
+ const { data: rsp_obj } = res
24
+ res.data = {
25
+ HttpStatusCode: rsp_obj.code,
26
+ Error: rsp_obj.errMsg,
27
+ IsError: !rsp_obj.success,
28
+ Data:
29
+ rsp_obj.data && Object.keys(rsp_obj.data).length
30
+ ? {
31
+ HasCompany: rsp_obj.data.hasCompanyState > 0, // BaseInfoV1和BaseInfo的差别
32
+ Id: rsp_obj.data.id || '',
33
+ UId: rsp_obj.data.userId || 0,
34
+ UserName: rsp_obj.data.userName || '',
35
+ NickName: rsp_obj.data.nickName || '',
36
+ Email: rsp_obj.data.userEmail || '',
37
+ EmailIsCheck: rsp_obj.data.emailCheckState > 0,
38
+ RegionCode: rsp_obj.data.regionCode || '',
39
+ Phone: rsp_obj.data.userPhone || '',
40
+ PhoneIsCheck: rsp_obj.data.phoneCheckState > 0,
41
+ HeadUrl: rsp_obj.data.headUrl || '',
42
+ BackImage: rsp_obj.data.backImage || '',
43
+ BriefIntro: rsp_obj.data.briefIntro || '',
44
+ Industry: rsp_obj.data.industryId || 0,
45
+ Source: rsp_obj.data.registerSource || 0,
46
+ ShowName: rsp_obj.data.showName || '',
47
+ HeadIsDef: rsp_obj.data.headDefState > 0,
48
+ Nick: rsp_obj.data.nick || '',
49
+ NickShowName: rsp_obj.data.nickShowName || '',
50
+ RegDate: rsp_obj.data.registerDate || '',
51
+ }
52
+ : {},
53
+ }
54
+ return res
55
+ })
56
+ }
57
+
58
+ async function getUserInfo(opts, signArr) {
59
+ const typeArr = ['BaseInfo', 'BaseInfoV1', 'ExtendInfo', 'userInfo']
60
+ if (!typeArr.includes(opts.__type__)) {
61
+ opts.__type__ = typeArr[0]
62
+ }
63
+ if (opts.__type__ === 'userInfo') {
64
+ return userInfo(opts, signArr)
65
+ } else {
66
+ return baseInfo(opts, signArr)
67
+ }
68
+ }
69
+
70
+ exports = module.exports = {
71
+ getUserInfo,
72
+ }