Skip to content

Commit

Permalink
feat: 完成微信公众号登录,支持场景二维码/验证码回复两种登录模式
Browse files Browse the repository at this point in the history
perf: 移除bun,改用pnpm
  • Loading branch information
liuhuapiaoyuan committed Nov 16, 2024
1 parent 52d2d12 commit a04a6f2
Show file tree
Hide file tree
Showing 20 changed files with 6,465 additions and 111 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/docs-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ jobs:
uses: actions/configure-pages@v4

- name: Install dependencies
run: bun i # 或 pnpm install / yarn install / bun install
run: bun i # 或 pnpm install / yarn install / bun install

- name: Build with VitePress
run: bun docs:build # 或 pnpm docs:build / yarn docs:build / bun run docs:build
run: bun docs:build # 或 pnpm docs:build / yarn docs:build / pnpm run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
Expand All @@ -62,4 +62,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v4
9 changes: 4 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
on:
push:
tags:
- "*"
- '*'
workflow_dispatch:

name: publish-npm
Expand All @@ -11,17 +11,16 @@ jobs:
runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v2

- name: setup bun
uses: oven-sh/setup-bun@v2

- name: install app dependencies and build it
run: bun i && bun run build
run: bun i && pnpm run build

- name: publish to npm
run: bun run release
run: pnpm run release
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "bun run example:dev"
"command": "pnpm run example:dev"
},
{
"name": "Next.js: debug client-side",
Expand Down
8 changes: 4 additions & 4 deletions apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
"@radix-ui/react-tabs": "^1.1.1",
"class-variance-authority": "*",
"clsx": "^2.1.1",
"next": "15.0.1",
"next": "15.0.3",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"next-auth": "beta",
"next-auth-oauth": "^1",
"@next-auth-oauth/wechatmp": "*",
"@next-auth-oauth/wechatmp": "workspace:*",
"wechatmp-kit": "*",
"react": "19.0.0-rc-cae764ce-20241025",
"react-dom": "19.0.0-rc-cae764ce-20241025",
"tailwind-merge": "^2.5.2"
},
"devDependencies": {
Expand Down
7 changes: 3 additions & 4 deletions apps/example/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ export const wechatMpProvder = Wehcatmp({
appSecret: process.env.AUTH_WECHATMP_APPSECRET!,
}),
endpoint: 'http://localhost:3000/api/auth/wechatmp',
/**
* 通过消息回复
*/
checkType: 'QRCODE',
qrcodeImageUrl:
'https://oauth.chanlun.ggss.club/uploads/20240121/3fec8aa97489ad13a734c500038822a3.jpg',
})

export const authService = new AuthService()
export const {
handlers,
Expand Down
Binary file removed bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions docs/wechatmp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Nextjs面向国内编程:快速集成`微信公众号扫码/验证码`登录
31 changes: 16 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,31 @@
"apps/*"
],
"scripts": {
"docs:dev": "bun --filter 'docs' docs:dev",
"docs:build": "bun --filter 'docs' docs:build",
"build": "bun --filter 'next-auth-oauth' build",
"release": "bun --filter 'next-auth-oauth' release",
"dev": "bun --filter '{next-auth-oauth,example}' dev",
"example:build": "bun run --filter '{next-auth-oauth,@next-auth-oauth/wechatmp,@next-auth-oauth/gitee,example}' build",
"example:dev": "bun run --filter 'example' dev",
"release:wechatmp-kit": "bun run --filter 'wechatmp-kit' release ",
"release:weibo": "bun run --filter '@next-auth-oauth/weibo' release ",
"release:gitee": "bun run --filter '@next-auth-oauth/gitee' release ",
"release:authing": "bun run --filter '@next-auth-oauth/authing' release ",
"release:qq": "bun run --filter '@next-auth-oauth/qq' release ",
"release:wechat": "bun run --filter '@next-auth-oauth/wechat' release ",
"release:providers": "bun run --filter '@next-auth-oauth/*' release "
"docs:dev": "pnpm --filter 'docs' docs:dev",
"docs:build": "pnpm --filter 'docs' docs:build",
"build": "pnpm --filter 'next-auth-oauth' build",
"release": "pnpm --filter 'next-auth-oauth' release",
"dev": "pnpm --filter '{next-auth-oauth,example}' dev",
"example:build": "pnpm run --filter '{next-auth-oauth,@next-auth-oauth/wechatmp,@next-auth-oauth/gitee,example}' build",
"example:dev": "pnpm run --filter example dev",
"release:wechatmp-kit": "pnpm run --filter 'wechatmp-kit' release ",
"release:weibo": "pnpm run --filter '@next-auth-oauth/weibo' release ",
"release:gitee": "pnpm run --filter '@next-auth-oauth/gitee' release ",
"release:authing": "pnpm run --filter '@next-auth-oauth/authing' release ",
"release:qq": "pnpm run --filter '@next-auth-oauth/qq' release ",
"release:wechat": "pnpm run --filter '@next-auth-oauth/wechat' release ",
"release:providers": "pnpm run --filter '@next-auth-oauth/*' release "
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/bun": "latest",
"@types/node": "^20",
"@commitlint/config-conventional": "^19.5.0",
"commitlint": "^19.5.0",
"prettier": "3.3.3",
"eslint": "^8.57.1",
"typescript": "^5",
"eslint-config-prettier": "^9.1.0"
},
"publishConfig": {
Expand Down
4 changes: 2 additions & 2 deletions packages/authing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand All @@ -35,4 +35,4 @@
"access": "public",
"registry": "https://registry.npmjs.org"
}
}
}
2 changes: 1 addition & 1 deletion packages/gitee/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target node --outdir dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand Down
4 changes: 2 additions & 2 deletions packages/qq/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand All @@ -34,4 +34,4 @@
"access": "public",
"registry": "https://registry.npmjs.org"
}
}
}
2 changes: 1 addition & 1 deletion packages/wechat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand Down
4 changes: 2 additions & 2 deletions packages/wechatmp-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"scripts": {
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"wechat",
Expand All @@ -29,4 +29,4 @@
"license": "MIC",
"peerDependencies": {},
"devDependencies": {}
}
}
6 changes: 3 additions & 3 deletions packages/wechatmp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
"docs"
],
"scripts": {
"dev": "tsc --declaration --emitDeclarationOnly && bun build ./src/index.ts --target=node --outdir=dist --watch",
"build": "bun build ./src/index.ts --target=node --outdir=dist && tsc --declaration --emitDeclarationOnly",
"dev": "tsc --watch",
"build": "tsc",
"patch:version": "npm version patch",
"release": "bun run build && npm publish && npm version patch"
"release": "pnpm run build && npm publish && npm version patch"
},
"keywords": [
"nextjs",
Expand Down
101 changes: 37 additions & 64 deletions packages/wechatmp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ import type {
} from 'next-auth/providers'
import { WechatMpApi } from 'wechatmp-kit'
import { CaptchaManager } from './lib/CaptchaManager'
import { QrcodePage } from './pages/qrcode'

export type WechatPlatformConfig = {
/**
* 验证类型 "MESSAGE"|"QRCODE"
* MESSAGE 回复消息
* QRCODE 临时二维码
* - MESSAGE 回复消息
* - QRCODE 临时二维码
* - 默认使用环境变量 AUTH_WECHATMP_CHECKTYPE
* @default "MESSAGE"
*/
checkType: 'MESSAGE' | 'QRCODE'
checkType?: 'MESSAGE' | 'QRCODE'

/**
* 二维码图片地址
* checkType为MESSAGE时必须配置此参数
* ### 一般为**公众号关注二维码**
* ##### 用于引导用户扫码关注公众号后,方便发送验证码
* ##### 当checkType为MESSAGE时必须配置此参数
*/
qrcodeImageUrl?: string
/**
Expand All @@ -33,8 +36,9 @@ export type WechatPlatformConfig = {
* 页面接口,包含:
* - 二维码展示页面
* - 微信消息回调页面
* 默认使用环境变量 AUTH_WECHATMP_ENDPOINT
*/
endpoint: string
endpoint?: string
}

export type WechatMpProfile = {
Expand Down Expand Up @@ -77,8 +81,10 @@ export default function WeChatMp<P extends WechatMpProfile>(
): OAuth2Config<P> & WechatMpResult {
const { wechatMpApi, checkType, endpoint, qrcodeImageUrl } = Object.assign(
{
endpoint: process.env.AUTH_WECHATMP_ENDPOINT,
checkType: 'MESSAGE',
endpoint:
process.env.AUTH_WECHATMP_ENDPOINT ??
'http://localhost:3000/api/auth/wechatmp',
checkType: process.env.AUTH_WECHATMP_CHECKTYPE ?? 'MESSAGE',
},
options ?? {},
)
Expand Down Expand Up @@ -150,7 +156,7 @@ export default function WeChatMp<P extends WechatMpProfile>(
async function GET(request: Request): Promise<Response> {
const link = new URL(request.url)
const action = link.searchParams.get('action')
const redirectUri = link.searchParams.get('redirect_uri')
const redirectUri = link.searchParams.get('redirect_uri')!
// 微信消息验证
const timestamp = link.searchParams.get('timestamp')
const nonce = link.searchParams.get('nonce')
Expand All @@ -164,56 +170,19 @@ export default function WeChatMp<P extends WechatMpProfile>(
}
if (action === 'qrcode') {
const code = await captchaManager.generate()
let imgLink = qrcodeImageUrl
let imgLink = qrcodeImageUrl!
if (checkType === 'QRCODE') {
const t = await messageServicde.createPermanentQrcode(code)
imgLink = `https://zddydd.com/qrcode/build?label=&logo=0&labelalignment=center&foreground=%23000000&background=%23ffffff&size=300&padding=10&logosize=50&labelfontsize=14&errorcorrection=medium&text=${encodeURI(t.url)}`
//imgLink = `https://zddydd.com/qrcode/build?label=&logo=0&labelalignment=center&foreground=%23000000&background=%23ffffff&size=300&padding=10&logosize=50&labelfontsize=14&errorcorrection=medium&text=${encodeURI(t.url)}`
imgLink = t.url
}
const html = `
<html>
<head>
<title>微信公众号登录</title>
</head>
<body style="display:flex;justify-content:center;align-items:center;height:100vh;width:100vw;margin:0;background:#525252;">
<div style="padding:5px;border-radius:10px;text-align:center;background-color:white;">
<p>请使用微信扫描二维码登录</p>
<img src="${imgLink}">
</div>
<script>
// 模拟的API URL,用于检查登录状态
const checkLoginUrl = '${endpoint}?action=check';
// 登录成功后的跳转URL
const successRedirectUrl = '${redirectUri}?code=${code}';
function checkLoginStatus() {
fetch(checkLoginUrl, {
method: 'POST',
body: JSON.stringify({
code: '${code}'
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.type=='success') {
alert("登录成功");
window.location.href = successRedirectUrl;
} else {
console.log('登录未成功');
}
})
.catch(error => {
console.error('请求过程中出现错误:', error);
});
}
setInterval(checkLoginStatus, 5000);
</script>
</body>
</html>
`
const html = QrcodePage({
checkType,
qrcode: imgLink,
code,
redirectUri,
endpoint,
})
return new Response(html, {
headers: {
'Content-Type': 'text/html',
Expand Down Expand Up @@ -246,16 +215,20 @@ export default function WeChatMp<P extends WechatMpProfile>(
})
} else if (action === 'check') {
const { code } = await request.json()
const valid = await captchaManager.validCode(code)
if (valid?.openid) {
return Response.json({ type: 'success' })
try {
const valid = await captchaManager.validCode(code)
if (valid?.openid) {
return Response.json({ type: 'success' })
}
} catch (_) {
return Response.json({ type: 'fail' })
}
return Response.json({ type: 'fail' })
return Response.json({ type: 'checking' })
}

const timestamp = link.searchParams.get('timestamp')
const nonce = link.searchParams.get('nonce')
const signature = link.searchParams.get('signature')
const timestamp = link.searchParams.get('timestamp')!
const nonce = link.searchParams.get('nonce')!
const signature = link.searchParams.get('signature')!
const echo = link.searchParams.get('echostr')
if (timestamp && nonce && signature && echo) {
if (messageServicde.checkSign({ timestamp, nonce, signature })) {
Expand All @@ -272,7 +245,7 @@ export default function WeChatMp<P extends WechatMpProfile>(
signature: msg_signature ?? signature,
})
let content = ''
if (message.MsgType == 'event') {
if (message.EventKey && message.MsgType == 'event') {
content = message.EventKey.replace('qrscene_', '')
} else if (message.MsgType == 'text') {
content = message.Content.trim()
Expand Down
Loading

0 comments on commit a04a6f2

Please sign in to comment.