-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
LiuSongJiang
committed
Apr 8, 2019
1 parent
59d4ba8
commit a9836ad
Showing
16 changed files
with
246 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file was deleted.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,26 @@ | ||
import * as requireAll from 'require-all'; | ||
import * as requireAll from "require-all"; | ||
import * as Hapi from "hapi"; | ||
|
||
// 自动引入routes.js | ||
const allApi: object = requireAll({ | ||
dirname: __dirname, | ||
filter: /routes.js$/, | ||
}) | ||
filter: /routes.js$/ | ||
}); | ||
|
||
const routes = []; | ||
export default (server: Hapi.Server): Hapi.Server => { | ||
const routes = []; | ||
|
||
function reduceRoute(routeNote: object) { | ||
Object.values(routeNote).forEach((route = {}) => { | ||
const module = route['routes.js'] || []; | ||
if (module) { | ||
const [moduleDefault] = module.default | ||
routes.push(moduleDefault); | ||
} | ||
}); | ||
} | ||
function reduceRoute(routeNote: object) { | ||
Object.values(routeNote).forEach((route = {}) => { | ||
const module = route["routes.js"]; | ||
if (module) { | ||
const [moduleDefault] = module.default(server); | ||
routes.push(moduleDefault); | ||
} | ||
}); | ||
} | ||
|
||
reduceRoute(allApi) | ||
|
||
|
||
export default routes; | ||
reduceRoute(allApi); | ||
|
||
return server.route(routes); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import * as Hapi from "hapi"; | ||
import axios from "axios"; | ||
import * as JWT from "jsonwebtoken"; | ||
import { IMixinsServerWechat } from "../../interfaces/config"; | ||
import { IWxLoginRquest, IWxLoginParams } from "./interfaces"; | ||
import decryptData from "../../utils/decrypted-data"; | ||
import Users, { IUsers } from "../../db/models/users.model"; | ||
|
||
export default class WxLoginController { | ||
private config: IMixinsServerWechat; | ||
private model = Users; | ||
private wxSessionUrl = "https://api.weixin.qq.com/sns/jscode2session"; | ||
private grant_type = "authorization_code"; | ||
|
||
constructor(conifg: IMixinsServerWechat) { | ||
this.config = conifg; | ||
} | ||
|
||
public async wxLogin(request: IWxLoginRquest, h: Hapi.ResponseToolkit) { | ||
const appid = this.config.wxAppid; // 小程序 appid | ||
const secret = this.config.wxSecret; // 小程序 appsecret | ||
|
||
const { code, encryptedData, iv } = request.payload; | ||
|
||
const { openid, sessionKey } = await this.getOpid({ | ||
appid, | ||
secret, | ||
js_code: code, | ||
grant_type: this.grant_type | ||
}); | ||
|
||
const user = await this.model.findOrCreate({ | ||
where: { open_id: openid } | ||
}); | ||
|
||
const userInfo = decryptData(encryptedData, iv, sessionKey, appid); | ||
|
||
await this.updateUser( | ||
{ | ||
nick_name: userInfo.nickName, | ||
gender: userInfo.gender, | ||
avatar_url: userInfo.avatarUrl, | ||
open_id: openid, | ||
session_key: sessionKey | ||
}, | ||
openid | ||
); | ||
|
||
const token = { token: this.generateToken(user[0].id) }; | ||
|
||
return token; | ||
} | ||
|
||
public async updateUser(updateData: IUsers, openid: string) { | ||
await this.model.update(updateData, { | ||
where: { open_id: openid } | ||
}); | ||
} | ||
|
||
private generateToken(userId: number) { | ||
const payload = { | ||
id: userId | ||
}; | ||
const jwtSecret = this.config.jwtSecret; | ||
const jwtExpiration = this.config.jwtExpiration; | ||
return JWT.sign(payload, jwtSecret, { expiresIn: jwtExpiration }); | ||
} | ||
|
||
// 通过微信服务器获取opid | ||
private async getOpid(params: IWxLoginParams) { | ||
const response = await axios({ | ||
url: this.wxSessionUrl, | ||
method: "GET", | ||
params | ||
}); | ||
const { openid, session_key: sessionKey } = response.data; | ||
return { openid, sessionKey }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export interface IWxLoginRquest { | ||
payload: { | ||
code: string; | ||
encryptedData: string; | ||
iv: string; | ||
}; | ||
} | ||
|
||
export interface IWxLoginParams { | ||
appid: string; | ||
secret: string; | ||
js_code: string; | ||
grant_type: string; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import * as Hapi from "hapi"; | ||
import { getWeChatConfigs, getServerConfigs } from "../../configurations"; | ||
import { | ||
IMixinsServerWechat, | ||
IWeChatConifg, | ||
IServerConfigurations | ||
} from "../../interfaces/config"; | ||
import WxLoginController from "./controller"; | ||
import { wxLogin } from "./validator"; | ||
|
||
export default (server: Hapi.Server) => { | ||
const weChatConfig: IWeChatConifg = getWeChatConfigs(); | ||
const serverConfig: IServerConfigurations = getServerConfigs(); | ||
const configs: IMixinsServerWechat = { ...weChatConfig, ...serverConfig }; | ||
const loginController = new WxLoginController(configs); | ||
server.bind(loginController); | ||
|
||
return [ | ||
{ | ||
method: "POST", | ||
path: "/wxLogin", | ||
handler: loginController.wxLogin, | ||
config: { | ||
auth: false, // 不需要用户验证 | ||
tags: ["api", "GROUP_NAME"], | ||
description: "创建订单", | ||
validate: { | ||
payload: wxLogin | ||
} | ||
} | ||
} | ||
]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import * as Joi from "joi"; | ||
|
||
export const wxLogin = Joi.object().keys({ | ||
code: Joi.string() | ||
.required() | ||
.description("微信用户登录的临时code"), | ||
|
||
encryptedData: Joi.string() | ||
.required() | ||
.description("微信用户信息encryptedData"), | ||
|
||
iv: Joi.string() | ||
.required() | ||
.description("微信用户信息iv") | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// 封装的 decryptData,用于解码小程序的 encryptData | ||
import * as crypto from "crypto"; | ||
|
||
export interface IDecodeUserData { | ||
avatarUrl: string; | ||
gender: number; | ||
nickName: string; | ||
watermark: { | ||
appid: string; | ||
}; | ||
} | ||
|
||
function decryptData( | ||
encryptedData: string, | ||
iv: string, | ||
sessionKey: string, | ||
appid: string | ||
) { | ||
// base64 decode | ||
const encryptedDataNew = Buffer.from(encryptedData, "base64"); | ||
const sessionKeyNew = Buffer.from(sessionKey, "base64"); | ||
const ivNew = Buffer.from(iv, "base64"); | ||
|
||
let decoded = ""; | ||
let decodeData: IDecodeUserData; | ||
try { | ||
// 解密,使用的算法是 aes-128-cbc | ||
const decipher = crypto.createDecipheriv( | ||
"aes-128-cbc", | ||
sessionKeyNew, | ||
ivNew | ||
); | ||
// 设置自动 padding 为 true,删除填充补位 | ||
decipher.setAutoPadding(true); | ||
decoded = decipher.update(encryptedDataNew, undefined, "utf8"); | ||
decoded += decipher.final("utf8"); | ||
decodeData = JSON.parse(decoded); | ||
// decoded 是解密后的用户信息 | ||
} catch (err) { | ||
throw new Error("Illegal Buffer" + err); | ||
} | ||
|
||
// 解密后的用户数据中会有一个 watermark 属性,这个属性中包含这个小程序的 appid 和时间戳,下面是校验 appid | ||
if (decodeData.watermark.appid !== appid) { | ||
throw new Error("Illegal Buffer"); | ||
} | ||
|
||
// 返回解密后的用户数据 | ||
return decodeData; | ||
} | ||
|
||
export default decryptData; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import * as Joi from 'joi'; | ||
|
||
export const paginationDefine = { | ||
limit: Joi.number().integer().min(1).default(10) | ||
.description('每页的条目数'), | ||
page: Joi.number().integer().min(1).default(1) | ||
.description('页码数'), | ||
pagination: Joi.boolean().description('是否开启分页,默认为true'), | ||
} | ||
|
||
export const jwtHeaderDefine = { | ||
headers: Joi.object({ | ||
authorization: Joi.string().required(), | ||
}).unknown(), | ||
} |