fix: add wx-login check
This commit is contained in:
parent
197d6415d3
commit
e5111227fd
@ -5,7 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"basename": "/root/wx-app-services",
|
"basename": "/root/wx-app-services",
|
||||||
"app": {
|
"app": {
|
||||||
"key": "wx-app",
|
"key": "wx-app-services",
|
||||||
"entry": "dist/app.mjs",
|
"entry": "dist/app.mjs",
|
||||||
"type": "system-app",
|
"type": "system-app",
|
||||||
"files": [
|
"files": [
|
||||||
|
@ -24,10 +24,10 @@ export type WxToken = {
|
|||||||
* @param code
|
* @param code
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchToken = async (code: string): Promise<WxToken> => {
|
export const fetchToken = async (code: string, type: 'open' | 'mp' = 'open'): Promise<WxToken> => {
|
||||||
let appId = config.wxOpen.appId;
|
let appId = config.wxOpen.appId;
|
||||||
let appSecret = config.wxOpen.appSecret;
|
let appSecret = config.wxOpen.appSecret;
|
||||||
if (!appId && !appSecret) {
|
if (type === 'mp') {
|
||||||
appId = config.wx.appId;
|
appId = config.wx.appId;
|
||||||
appSecret = config.wx.appSecret;
|
appSecret = config.wx.appSecret;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ app
|
|||||||
const code = ctx.query.code;
|
const code = ctx.query.code;
|
||||||
try {
|
try {
|
||||||
const wx = new WxServices();
|
const wx = new WxServices();
|
||||||
const token = await wx.login(code);
|
const token = await wx.login(code, 'mp');
|
||||||
const redis = useContextKey('redis');
|
const redis = useContextKey('redis');
|
||||||
await redis.set(`wx:mp:login:${state}`, token, 'EX', 10000); // 30秒过期
|
await redis.set(`wx:mp:login:${state}`, token, 'EX', 10000); // 30秒过期
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
@ -81,6 +81,24 @@ app
|
|||||||
})
|
})
|
||||||
.addTo(app);
|
.addTo(app);
|
||||||
|
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'wx',
|
||||||
|
key: 'mp-get-openid',
|
||||||
|
isDebug: true,
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const code = ctx.query.code;
|
||||||
|
if (!code) {
|
||||||
|
ctx.throw(400, 'code is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const wx = new WxServices();
|
||||||
|
const mpInfo = await wx.getOpenid(code, 'mp');
|
||||||
|
ctx.body = mpInfo;
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
|
||||||
app
|
app
|
||||||
.route({
|
.route({
|
||||||
path: 'wx',
|
path: 'wx',
|
||||||
|
@ -36,8 +36,22 @@ export class WxServices {
|
|||||||
}
|
}
|
||||||
return random;
|
return random;
|
||||||
}
|
}
|
||||||
async login(code: string) {
|
/**
|
||||||
const token = await fetchToken(code);
|
* 获取openid
|
||||||
|
* @param code
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async getOpenid(code: string, type: 'mp' | 'open' = 'open') {
|
||||||
|
const token = await fetchToken(code, type);
|
||||||
|
console.log('login token', token);
|
||||||
|
return {
|
||||||
|
openid: token.openid,
|
||||||
|
scope: token.scope,
|
||||||
|
unionid: token.unionid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async login(code: string, type: 'mp' | 'open' = 'open') {
|
||||||
|
const token = await fetchToken(code, type);
|
||||||
console.log('login token', token);
|
console.log('login token', token);
|
||||||
if (!token.unionid) {
|
if (!token.unionid) {
|
||||||
throw new CustomError(400, 'code is invalid, wxdata can not be found');
|
throw new CustomError(400, 'code is invalid, wxdata can not be found');
|
||||||
@ -52,32 +66,49 @@ export class WxServices {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (user && user.data.wxOpenid !== token.openid) {
|
if (type === 'open' && user && user.data.wxOpenid !== token.openid) {
|
||||||
user.data = {
|
user.data = {
|
||||||
...user.data,
|
...user.data,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
wxOpenid: token.openid,
|
wxOpenid: token.openid,
|
||||||
};
|
};
|
||||||
await user.update({ data: user.data });
|
user = await user.update({ data: user.data });
|
||||||
console.log('mp-user login openid update=============', token.openid, token.unionid);
|
console.log('mp-user login openid update=============', token.openid, token.unionid);
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (type === 'mp' && user && user.data.wxmpOpenid !== token.openid) {
|
||||||
|
user.data = {
|
||||||
|
...user.data,
|
||||||
|
// @ts-ignore
|
||||||
|
wxmpOpenid: token.openid,
|
||||||
|
};
|
||||||
|
user = await user.update({ data: user.data });
|
||||||
}
|
}
|
||||||
if (!user) {
|
if (!user) {
|
||||||
const username = await this.randomUsername();
|
const username = await this.randomUsername();
|
||||||
user = await User.createUser(username, nanoid(10));
|
user = await User.createUser(username, nanoid(10));
|
||||||
user.data = {
|
let data = {
|
||||||
...user.data,
|
...user.data,
|
||||||
// @ts-ignore
|
|
||||||
wxOpenid: token.openid,
|
|
||||||
wxUnionId: unionid,
|
wxUnionId: unionid,
|
||||||
};
|
};
|
||||||
await user.save({ fields: ['data'] });
|
user.data = data;
|
||||||
|
if ((type = 'mp')) {
|
||||||
|
// @ts-ignore
|
||||||
|
data.wxmpOpenid = token.openid;
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
data.wxOpenid = token.openid;
|
||||||
|
}
|
||||||
|
this.user = await user.save({ fields: ['data'] });
|
||||||
|
|
||||||
|
this.getUserInfo();
|
||||||
this.isNew = true;
|
this.isNew = true;
|
||||||
}
|
}
|
||||||
|
this.user = user;
|
||||||
const tokenInfo = await user.createToken(null, 'plugin', {
|
const tokenInfo = await user.createToken(null, 'plugin', {
|
||||||
wx: {
|
wx: {
|
||||||
openid: token.openid,
|
openid: token.openid,
|
||||||
unionid: unionid,
|
unionid: unionid,
|
||||||
|
type,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.webToken = tokenInfo.accessToken;
|
this.webToken = tokenInfo.accessToken;
|
||||||
@ -107,7 +138,12 @@ export class WxServices {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error downloading or converting image:', error);
|
console.error('Error downloading or converting image:', error);
|
||||||
}
|
}
|
||||||
await this.user.save();
|
const data = {
|
||||||
|
...this.user.data,
|
||||||
|
wxUserInfo: userInfo,
|
||||||
|
};
|
||||||
|
this.user.data = data;
|
||||||
|
await this.user.save({ fields: ['data', 'nickname', 'avatar'] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting user info:', error);
|
console.error('Error getting user info:', error);
|
||||||
}
|
}
|
||||||
@ -121,7 +157,7 @@ export class WxServices {
|
|||||||
return await downloadImag(url);
|
return await downloadImag(url);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error downloading or converting image:', error);
|
console.error('Error downloading or converting image:', error);
|
||||||
throw error;
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
mini-web/README.md
Normal file
3
mini-web/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# 登陆逻辑
|
||||||
|
|
||||||
|
微信访问 `login.html` 的界面, 然后 `login.html` 去获取 `/authorize` 获取 openid
|
@ -3,9 +3,15 @@ export const config = {
|
|||||||
appid: 'wxff97d569b1db16b6',
|
appid: 'wxff97d569b1db16b6',
|
||||||
appid_open: 'wx9378885c8390e09b', // 公众开放平台, 逸文设计 //
|
appid_open: 'wx9378885c8390e09b', // 公众开放平台, 逸文设计 //
|
||||||
redirect_uri: 'https://kevisual.xiongxiao.me/root/mini-web/callback.html',
|
redirect_uri: 'https://kevisual.xiongxiao.me/root/mini-web/callback.html',
|
||||||
scope: 'snsapi_userinfo',
|
scope: 'snsapi_userinfo', // 授权作用域, 默认是snsapi_base
|
||||||
};
|
};
|
||||||
|
|
||||||
export const loginUrl = `https://kevisual.xiongxiao.me/root/mini-web/login.html`;
|
export const loginUrl = `https://kevisual.xiongxiao.me/root/mini-web/login.html`;
|
||||||
|
|
||||||
export const loginSuccessUrl = `/apps/wallnote/`;
|
export const loginSuccessUrl = `/apps/wallnote/`;
|
||||||
|
|
||||||
|
export const openidConfig = {
|
||||||
|
appid: config.appid,
|
||||||
|
redirect_uri: 'https://kevisual.xiongxiao.me/root/mini-web/wx-get-openid.html',
|
||||||
|
scope: 'snsapi_base',
|
||||||
|
};
|
||||||
|
57
mini-web/envision/utils.js
Normal file
57
mini-web/envision/utils.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { openidConfig } from './config.js';
|
||||||
|
|
||||||
|
export const isWechat = () => {
|
||||||
|
const ua = navigator.userAgent.toLowerCase();
|
||||||
|
return /micromessenger/i.test(ua);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getOpenid = async () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const state = url.searchParams.get('state');
|
||||||
|
const code = url.searchParams.get('code');
|
||||||
|
const orgin = url.origin;
|
||||||
|
const res = await fetch(`${orgin}/api/router?path=wx&key=mp-get-openid&state=${state}&code=${code}`)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
alert('登录失败,请稍后再试');
|
||||||
|
document.body.append('登录失败,请稍后再试');
|
||||||
|
// closePage();
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
document.body.append(JSON.stringify(res.data, null, 2));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const checkHasCode = () => {
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const code = url.searchParams.get('code');
|
||||||
|
return code;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initGetOpenidEvent = () => {
|
||||||
|
if (!isWechat()) {
|
||||||
|
document.body.append('请在微信中打开');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hasCode = checkHasCode();
|
||||||
|
if (hasCode) {
|
||||||
|
getOpenid();
|
||||||
|
} else {
|
||||||
|
// 没有code,则跳转获取code
|
||||||
|
getCodeRedirect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const randomString = () => {
|
||||||
|
return Math.random().toString(36).substring(2, 15);
|
||||||
|
};
|
||||||
|
export const getCodeRedirect = () => {
|
||||||
|
const defaultURL = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect`;
|
||||||
|
const appid = openidConfig.appid;
|
||||||
|
const redirect_uri = encodeURIComponent(openidConfig.redirect_uri);
|
||||||
|
const scope = openidConfig.scope;
|
||||||
|
const state = randomString();
|
||||||
|
const link = defaultURL.replace('APPID', appid).replace('REDIRECT_URI', redirect_uri).replace('SCOPE', scope).replace('STATE', state);
|
||||||
|
window.location.href = link;
|
||||||
|
};
|
50
mini-web/envision/wx-get-openid.html
Normal file
50
mini-web/envision/wx-get-openid.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1, user-scalable=no">
|
||||||
|
<title>登录</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.5em;
|
||||||
|
/* Adjust font size for mobile */
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.loading {
|
||||||
|
font-size: 1em;
|
||||||
|
/* Smaller font size for smaller screens */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="loading"></div>
|
||||||
|
<div class="openid"></div>
|
||||||
|
<script type="module">
|
||||||
|
import { initGetOpenidEvent, isWechat } from './utils.js';
|
||||||
|
const loading = document.querySelector('.loading');
|
||||||
|
loading.textContent = !isWechat() ? '微信打开当前页面获取openid' : '';
|
||||||
|
initGetOpenidEvent();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "mini-web",
|
"name": "mini-web",
|
||||||
"version": "0.0.4",
|
"version": "0.0.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"basename": "/root/mini-web",
|
"basename": "/root/mini-web",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pub": "envision deploy ./envision -k mini-web -v 0.0.4 -y y",
|
"pub": "envision deploy ./envision -k mini-web -v 0.0.5 -u ",
|
||||||
"ev": "npm run build && npm run deploy"
|
"ev": "npm run build && npm run deploy"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user