feat: 完善微信登录
This commit is contained in:
@@ -5,6 +5,7 @@ import { ScheduleModule } from '@nestjs/schedule';
|
||||
import databaseConfig from './config/database.config';
|
||||
import jwtConfig from './config/jwt.config';
|
||||
import redisConfig from './config/redis.config';
|
||||
import wechatConfig from './config/wechat.config';
|
||||
import { ScheduleModule as TaskScheduleModule } from './schedule/schedule.module';
|
||||
|
||||
// 新的模块结构 - 按端分类
|
||||
@@ -20,7 +21,7 @@ import { WebsiteModule } from './modules/website/website.module';
|
||||
TaskScheduleModule,
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
load: [databaseConfig, jwtConfig, redisConfig],
|
||||
load: [databaseConfig, jwtConfig, redisConfig, wechatConfig],
|
||||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
TypeOrmModule.forRootAsync({
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('wechat', () => ({
|
||||
appId: process.env.WECHAT_APPID,
|
||||
appSecret: process.env.WECHAT_SECRET,
|
||||
}));
|
||||
@@ -239,18 +239,7 @@ export class AuthService {
|
||||
session_key: string;
|
||||
unionid?: string;
|
||||
}> {
|
||||
// 开发模式:返回模拟数据
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
if (isDev) {
|
||||
this.logger.log(`[DEV] 模拟微信登录: code=${code}`);
|
||||
return {
|
||||
openid: `dev_openid_${Date.now()}`,
|
||||
session_key: 'dev_session_key_1234567890abcdef',
|
||||
unionid: `dev_unionid_${Date.now()}`,
|
||||
};
|
||||
}
|
||||
|
||||
// 生产模式:调用微信API
|
||||
// 调用微信API
|
||||
const appId = this.configService.get<string>('wechat.appId');
|
||||
const appSecret = this.configService.get<string>('wechat.appSecret');
|
||||
|
||||
@@ -261,12 +250,17 @@ export class AuthService {
|
||||
const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${appSecret}&js_code=${code}&grant_type=authorization_code`;
|
||||
|
||||
try {
|
||||
this.logger.log(`调用微信API: appId=${appId}, code=${code.substring(0, 10)}...`);
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
|
||||
this.logger.log(`微信API响应: ${JSON.stringify(data)}`);
|
||||
|
||||
if (data.errcode) {
|
||||
this.logger.error(`微信API错误: ${data.errmsg}`);
|
||||
throw new BadRequestException('微信授权失败');
|
||||
const errorMsg = this.getWechatErrorMessage(data.errcode, data.errmsg);
|
||||
this.logger.error(`微信API错误 [${data.errcode}]: ${errorMsg}`);
|
||||
this.logger.error(`微信API错误 data : ${data}`);
|
||||
throw new BadRequestException(errorMsg);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -275,29 +269,35 @@ export class AuthService {
|
||||
unionid: data.unionid,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof BadRequestException) {
|
||||
throw error;
|
||||
}
|
||||
this.logger.error('调用微信API失败', error);
|
||||
throw new BadRequestException('微信授权失败');
|
||||
throw new BadRequestException('微信授权失败,请重试');
|
||||
}
|
||||
}
|
||||
|
||||
private getWechatErrorMessage(errcode: number, errmsg: string): string {
|
||||
const errorMap: Record<number, string> = {
|
||||
40029: '微信登录code无效,请重新授权',
|
||||
45011: '微信登录频率限制,请稍后再试',
|
||||
40163: 'code已被使用,请重新授权',
|
||||
};
|
||||
|
||||
if (errcode === -1) {
|
||||
return '微信系统繁忙,请稍后再试';
|
||||
}
|
||||
|
||||
return errorMap[errcode] || `微信授权失败: ${errmsg}`;
|
||||
}
|
||||
|
||||
private decryptWechatData(
|
||||
encryptedData: string,
|
||||
iv: string,
|
||||
sessionKey: string,
|
||||
): any {
|
||||
try {
|
||||
// 开发模式:返回模拟数据
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
if (isDev) {
|
||||
this.logger.log('[DEV] 模拟解密微信手机号');
|
||||
return {
|
||||
phoneNumber: '13800138000',
|
||||
purePhoneNumber: '13800138000',
|
||||
countryCode: '86',
|
||||
};
|
||||
}
|
||||
|
||||
// 生产模式:解密数据
|
||||
// 解密数据
|
||||
const sessionKeyBuffer = Buffer.from(sessionKey, 'base64');
|
||||
const encryptedDataBuffer = Buffer.from(encryptedData, 'base64');
|
||||
const ivBuffer = Buffer.from(iv, 'base64');
|
||||
|
||||
Reference in New Issue
Block a user