Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/chf007/nestjs-wechat-work
企业微信 NestJS 工具包,目前主要包括企业微信 API 的 Service 封装、登录校验守卫(JWT实现)、扫码登录支持等功能。
https://github.com/chf007/nestjs-wechat-work
nestjs wechat-work
Last synced: 14 days ago
JSON representation
企业微信 NestJS 工具包,目前主要包括企业微信 API 的 Service 封装、登录校验守卫(JWT实现)、扫码登录支持等功能。
- Host: GitHub
- URL: https://github.com/chf007/nestjs-wechat-work
- Owner: chf007
- License: mit
- Created: 2020-03-04T08:23:57.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-02-28T04:31:42.000Z (9 months ago)
- Last Synced: 2024-10-20T08:05:16.506Z (26 days ago)
- Topics: nestjs, wechat-work
- Language: TypeScript
- Homepage:
- Size: 768 KB
- Stars: 37
- Watchers: 2
- Forks: 4
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# NestJS WechatWorkModule
企业微信 NestJS 工具包,目前主要包括企业微信 API 的 Service 封装、登录校验守卫(JWT 实现)、扫码登录支持等功能。
适用于使用企业微信的团队基于 NestJS 开发小型管理后台用。> access_token 缓存在内存中,每次调用企业微信 API 时先检查缓存,如果过期或失效则重新获取并缓存起来。
> 多实例应用各自维护缓存,机器少的情况下应该不会超出企业微信 API 频率限制。如果机器数很多,说明业务搞大了,恭喜你,到时候请换用别的解决方案或者 fork 代码自行扩展功能,例如使用中心化服务或使用 redis 缓存。
## 当前支持特性
* WechatWorkBaseService 企业微信 API 基本服务,包括获取 accessToken,按扫码返回的 code 查询用户 ID
* WechatWorkContactsService 企业微信 API 通讯录服务,目前只支持成员信息查询、部门信息查询,其它暂未添加
* WechatWorkAuthGuard 企业微信身份验证守卫,在需要的 Controller 或方法上添加
* WechatWorkAuthMiddleware 企业微信扫码登录中间件,按以下约定进行扫码登录流程:
* COOKIE 模式:
* 分为页面路由和 API 路由,页面路由如果没有登录直接跳企业微信扫码页,API 路由如果没有登录只返回错误码,是否跳转由前端来决定
* noRedirectPaths 用来配置 API 路由规则,符合此规则的不直接跳企业微信扫码页,只返回错误码,是否跳转由前端来决定
* WechatWorkAuthMiddleware 中间件会监控 loginPath 路由,如传入 code 则校验企业微信用户信息,正确则生成 jwt token,写入 cookie,然后跳转至 loginSuccessPath,如失败则跳至 loginFailPath;如直接访问,则直接跳转至企业微信扫码页
* loginSuccessPath 和 loginFailPath 对应的页面要自已实现
* WechatWorkAuthMiddleware 中间件会监控 logoutPath 路由,如访问,则清空 cookie,跳转至 loginSuccessPath。前端不访问这个页面也可以自行清除 cookie 达到登出的效果
* 会查询用户基本信息存储在 req 上下文中
* 身份验证使用 JsonWebToken 实现,一经签发,则在有效期内一直有效
* CALLBACK_TOKEN 模式:
* 分为页面路由和 API 路由,页面路由如果没有登录直接跳企业微信扫码页,API 路由如果没有登录只返回错误码,是否跳转由前端来决定
* noRedirectPaths 用来配置 API 路由规则,符合此规则的不直接跳企业微信扫码页,只返回错误码,是否跳转由前端来决定
* WechatWorkAuthMiddleware 中间件会监控 loginPath 路由,如传入 code 则校验企业微信用户信息,正确则生成 jwt token,然后跳转至 `${loginSuccessPath}[?|&]${tokenName}=token`,如失败则跳至 loginFailPath;如直接访问,则直接跳转至企业微信扫码页
* loginSuccessPath 和 loginFailPath 对应的页面要自已实现,loginSuccessPath 的页面要处理 url 中返回的 token
* WechatWorkAuthMiddleware 中间件不处理 logoutPath 路由。前端自行清除 token 达到登出的效果
* 会查询用户基本信息存储在 req 上下文中
* 身份验证使用 JsonWebToken 实现,一经签发,则在有效期内一直有效## 安装
```bash
npm install nestjs-wechat-work
```## 使用
### 导入 Module
#### 同步配置方式
```
// 导入 Module
import { Module } from '@nestjs/common';
import { WechatWorkModule } from 'nestjs-wechat-work';@Module({
imports: [
WechatWorkModule.register({
baseConfig: {
corpId: 'string', // 企业ID 必填
agentId: 'string', // 自建应用ID
agentSecret: 'string', // 自建应用secret
contactsSecret: 'string', // 通讯录secret
telephoneSecret: 'string', // 企业电话secret
scheduleSecret: 'string', // 日程secret
customerSecret: 'string', // 外部联系人secret
attendanceAgentId: 'string', // 打卡agent
attendanceSecret: 'string', // 打卡secret
approvalAgentId: 'string', // 审批agentId
approvalSecret: 'string', // 审批secret
hongbaoAgentId: 'string', // 企业红包agentId
hongbaoSecret: 'string', // 企业红包secret
},
authConfig: {
type: 'COOKIE', // auth 模式:COOKIE | CALLBACK_TOKEN,默认为 'COOKIE'
returnDomainName: 'https://admin.xxx.com', // 扫码回跳域名 必填
jwtSecret: 'adsadsad', // jwt secret 必填
loginPath: '/login', // 登陆处理 可以在 loginPath 中加一个 _loginFrom 参数,在 loginSuccessPath 中附上该参数,loginSuccessPath 可以再跳转到 _loginFrom 的地址(_loginFrom 可以是任意地址,loginSuccessPath 要做好白名单控制)
logoutPath: '/logout', // 登出处理
loginSuccessPath: '/', // 登陆成功后跳转地址
loginFailPath: '/login-fail.html', // 登陆失败后跳转地址,可以应用中自定义
noRedirectPaths: [ // 哪些开头的地址不直接跳转而是将控制权交给前端,
'/api/',
'/apiv2/',
],
tokenName: '_token', // token cookie name
tokenExpires: 3600 * 24 * 7, // token 过期秒数
cookieHttpOnly: true, // COOKIE 模式下是否对 cookie 启用 httpOnly 模式,默认是 true,为了安全建议设为 true
},
}),
],
providers: [],
})
export class AppModule {}```
#### 异步配置方式
适用于配置项从别的异步服务取得的场景
```
// 导入 Module
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { WechatWorkModule } from 'nestjs-wechat-work';@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
WechatWorkModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
baseConfig: {
corpId: configService.get('WECHAT_WORK_CORP_ID'), // 企业ID 必填
agentId: configService.get('WECHAT_WORK_AGENT_ID'), // 自建应用ID
agentSecret: configService.get('WECHAT_WORK_AGENT_SECRET'), // 自建应用secret
contactsSecret: configService.get('WECHAT_WORK_CONTACTS_SECRET'), // 通讯录secret
},
authConfig: {
type: 'COOKIE', // auth 模式:COOKIE | CALLBACK_TOKEN,默认为 'COOKIE'
returnDomainName: configService.get('WECHAT_WORK_RETURN_DOMAIN_NAME'), // 扫码回跳域名 必填
jwtSecret: configService.get('WECHAT_WORK_JWT_SECRET'), // jwt secret 必填
loginPath: '/usm/api/login', // 登陆处理
logoutPath: '/usm/api/logout', // 登出处理
loginSuccessPath: '/usm/', // 登陆成功后跳转地址
loginFailPath: '/usm/login-fail', // 登陆失败后跳转地址,可以应用中自定义
noRedirectPaths: ['/usm/api/'], // 哪些开头的地址不直接跳转而是将控制权交给前端
tokenName: '_token', // token cookie name
tokenExpires: 3600 * 24 * 7, // token 过期秒数
},
}),
inject: [ConfigService],
}),
],
providers: [],
})
export class AppModule {}```
### 使用 Service
```
// 使用 Service
import { Controller, Get, UseGuards, } from '@nestjs/common';
import { WechatWorkBaseService, WechatWorkContactsService, } from 'nestjs-wechat-work';@Controller('api')
export class SomeController {
constructor(private readonly wechatWorkBaseService: WechatWorkBaseService, private readonly wechatWorkContactsService: WechatWorkContactsService) {}@Get('test')
async test() {
return await this.wechatWorkContactsService.getUserInfo('wechatwork userId');
}
}
```### 使用 Guard
```
// 使用 WechatWorkAuthGuard
import { Controller, Get, UseGuards, Req, Request, } from '@nestjs/common';
import { WechatWorkBaseService, WechatWorkContactsService, WechatWorkAuthGuard } from 'nestjs-wechat-work';@Controller('api')
export class SomeController {
constructor(private readonly wechatWorkBaseService: WechatWorkBaseService, private readonly wechatWorkContactsService: WechatWorkContactsService) {}@UseGuards(WechatWorkAuthGuard)
@Get('test')
async test(@Req() request: any) {
return await this.wechatWorkContactsService.getUserInfo(request.user.userId);
}
}
```