实现微信登录功能,首次使用自动保存用户信息
前端实现: - 修改auth.vue登录逻辑 - 使用getUserProfile获取微信用户信息 - 获取用户昵称和头像URL - 调用uni.login获取code - 将code和用户信息发送到后端 - 登录成功后保存完整用户信息到本地 后端实现: - 修改UserController登录接口 - 接收code参数而不是openId - 调用微信API jscode2session获取openId - 使用RestTemplate调用微信接口 - 支持配置微信appid和secret - 首次登录自动创建用户并保存到数据库 配置文件: - application.properties新增微信配置项 - wechat.appid: 微信小程序AppID - wechat.secret: 微信小程序AppSecret 功能特点: - 首次使用小程序自动获取微信用户信息 - 用户信息保存到user_info表 - 支持游客模式(未配置微信参数时) - 完整的错误处理和日志记录
This commit is contained in:
1 parent
5c8fcce387
commit
caac642120
3 files changed
+88
-28
No files matched your search
@@ -1,7 +1,9 @@
|
||||
package xuan.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import xuan.entity.UserInfo;
|
||||
import xuan.service.UserInfoService;
|
||||
|
||||
@@ -16,14 +18,41 @@ public class UserController {
|
||||
@Autowired
|
||||
private UserInfoService userInfoService;
|
||||
|
||||
@Value("${wechat.appid:}")
|
||||
private String appId;
|
||||
|
||||
@Value("${wechat.secret:}")
|
||||
private String appSecret;
|
||||
|
||||
@PostMapping("/login")
|
||||
public Map<String, Object> login(@RequestBody Map<String, Object> params) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
try {
|
||||
String openId = params.get("openId") != null ? params.get("openId").toString() : null;
|
||||
String code = params.get("code") != null ? params.get("code").toString() : null;
|
||||
String nickname = params.get("nickname") != null ? params.get("nickname").toString() : "微信用户";
|
||||
String avatarUrl = params.get("avatarUrl") != null ? params.get("avatarUrl").toString() : "";
|
||||
|
||||
String openId = null;
|
||||
|
||||
if (code != null && !code.isEmpty() && appId != null && !appId.isEmpty() && appSecret != null && !appSecret.isEmpty()) {
|
||||
String url = String.format(
|
||||
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
|
||||
appId, appSecret, code
|
||||
);
|
||||
|
||||
try {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> wxResult = restTemplate.getForObject(url, Map.class);
|
||||
|
||||
if (wxResult != null && wxResult.containsKey("openid")) {
|
||||
openId = (String) wxResult.get("openid");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("调用微信API失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (openId == null || openId.isEmpty()) {
|
||||
openId = "guest_" + System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@@ -15,3 +15,7 @@ spring.jpa.properties.hibernate.format_sql=true
|
||||
|
||||
# Logging
|
||||
logging.level.xuan=DEBUG
|
||||
|
||||
# WeChat Mini Program Configuration
|
||||
wechat.appid=your_wechat_appid_here
|
||||
wechat.secret=your_wechat_secret_here
|
||||
@@ -85,37 +85,64 @@ export default {
|
||||
|
||||
this.loading = true
|
||||
|
||||
uni.login({
|
||||
success: (loginRes) => {
|
||||
if (loginRes.code) {
|
||||
const openId = loginRes.code
|
||||
|
||||
api.userApi.loginOrRegister({
|
||||
openId: openId,
|
||||
nickname: this.nickname || '微信用户',
|
||||
avatarUrl: this.avatarUrl
|
||||
}).then(res => {
|
||||
this.loading = false
|
||||
if (res.success) {
|
||||
uni.setStorageSync('userId', res.data.userId)
|
||||
uni.setStorageSync('userInfo', JSON.stringify(res.data))
|
||||
uni.getUserProfile({
|
||||
desc: '用于完善用户资料',
|
||||
success: (profileRes) => {
|
||||
console.log('获取用户信息成功:', profileRes)
|
||||
|
||||
const userInfo = profileRes.userInfo
|
||||
const nickname = userInfo.nickName || this.nickname || '微信用户'
|
||||
const avatarUrl = userInfo.avatarUrl || this.avatarUrl
|
||||
|
||||
uni.login({
|
||||
success: (loginRes) => {
|
||||
if (loginRes.code) {
|
||||
console.log('获取code成功:', loginRes.code)
|
||||
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 1500)
|
||||
api.userApi.loginOrRegister({
|
||||
code: loginRes.code,
|
||||
nickname: nickname,
|
||||
avatarUrl: avatarUrl
|
||||
}).then(res => {
|
||||
this.loading = false
|
||||
if (res.success) {
|
||||
console.log('登录成功:', res.data)
|
||||
uni.setStorageSync('userId', res.data.userId)
|
||||
uni.setStorageSync('userInfo', JSON.stringify(res.data))
|
||||
uni.setStorageSync('userCoins', res.data.coins || 10)
|
||||
uni.setStorageSync('vipLevel', res.data.vipLevel || 0)
|
||||
uni.setStorageSync('username', res.data.username || res.data.nickname)
|
||||
uni.setStorageSync('userAvatar', res.data.avatarUrl)
|
||||
|
||||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||||
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: '/pages/index/index' })
|
||||
}, 1500)
|
||||
} else {
|
||||
uni.showToast({ title: res.error || '登录失败', icon: 'none' })
|
||||
}
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
console.error('登录失败:', err)
|
||||
uni.showToast({ title: '网络错误', icon: 'none' })
|
||||
})
|
||||
} else {
|
||||
uni.showToast({ title: res.error || '登录失败', icon: 'none' })
|
||||
this.loading = false
|
||||
uni.showToast({ title: '获取授权失败', icon: 'none' })
|
||||
}
|
||||
}).catch(() => {
|
||||
},
|
||||
fail: (err) => {
|
||||
this.loading = false
|
||||
uni.showToast({ title: '网络错误', icon: 'none' })
|
||||
})
|
||||
} else {
|
||||
this.loading = false
|
||||
uni.showToast({ title: '获取授权失败', icon: 'none' })
|
||||
}
|
||||
console.error('uni.login失败:', err)
|
||||
uni.showToast({ title: '登录失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
this.loading = false
|
||||
console.error('getUserProfile失败:', err)
|
||||
uni.showToast({ title: '获取用户信息失败', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user