RuoYi-Cloud微服务实战:手把手教你搞定微信小程序登录(含头像昵称获取避坑指南)
·
RuoYi-Cloud微服务实战:微信小程序登录全流程解析与避坑指南
微信生态已成为企业数字化转型的重要入口,而小程序登录作为用户身份认证的第一道关卡,其稳定性和安全性直接影响业务闭环的完整性。本文将基于RuoYi-Cloud微服务架构,深入剖析微信小程序登录的最新实现方案,特别针对2023年后微信API变更带来的技术挑战提供完整解决方案。
1. 环境准备与架构设计
在开始编码前,需要确保开发环境满足以下基础条件:
- RuoYi-Cloud版本:v3.6.0+(支持Spring Cloud Alibaba 2021.x)
- 小程序基础库:2.30.0+
- 数据库字段扩展:
ALTER TABLE sys_user ADD COLUMN `open_id` varchar(64) DEFAULT NULL COMMENT '微信openId'; ALTER TABLE sys_user ADD COLUMN `union_id` varchar(64) DEFAULT NULL COMMENT '微信unionId';
微服务环境下登录流程的特殊性体现在:
- 认证中心(auth)与服务分离带来的令牌传递问题
- OpenFeign远程调用时的安全认证处理
- 分布式会话管理方案的选择
典型调用链路如下:
小程序 → 获取code → 网关 → auth服务 → 微信接口 → system服务 → 用户数据返回
2. 小程序端关键实现
2.1 新版授权方案适配
由于微信官方已废弃getUserProfile接口,当前推荐采用头像昵称填写功能实现用户信息收集。在pages/login/login.vue中:
// 授权按钮需声明open-type
<button
open-type="chooseAvatar"
@chooseavatar="handleChooseAvatar"
class="avatar-wrapper"
>
<image :src="avatarUrl" mode="aspectFill"/>
</button>
<input
type="nickname"
v-model="nickName"
class="weui-input"
placeholder="请输入昵称"
>
对应的处理逻辑:
export default {
data() {
return {
avatarUrl: '/static/avatar-default.png',
nickName: ''
}
},
methods: {
handleChooseAvatar(e) {
this.avatarUrl = e.detail.avatarUrl
}
}
}
2.2 登录凭证获取优化
在api/login.js中扩展微信登录方法:
// 微信登录方法
export function wxLogin(code) {
return request({
url: '/auth/wxlogin',
headers: {
isToken: false,
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'post',
data: { code }
})
}
关键提示:微信服务器对code的有效期限制为5分钟,且每个code只能使用一次。建议前端在获取后立即调用接口,避免过期问题。
3. 微服务端核心逻辑
3.1 认证中心接口改造
在TokenController.java中新增处理入口:
@PostMapping("/wxlogin")
public R<LoginUser> wxLogin(@RequestBody WxLoginForm form) {
// 参数校验
if (StringUtils.isBlank(form.getCode())) {
return R.fail("登录凭证不能为空");
}
// 构建微信API请求URL
String url = String.format(
"https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
wxConfig.getAppId(),
wxConfig.getSecret(),
form.getCode()
);
// 使用RestTemplate调用微信接口
String response = restTemplate.getForObject(url, String.class);
JSONObject json = JSON.parseObject(response);
// 错误处理
if (json.containsKey("errcode")) {
log.error("微信登录失败: {}", json.getString("errmsg"));
return R.fail("微信认证服务异常");
}
String openid = json.getString("openid");
String sessionKey = json.getString("session_key");
// 通过Feign客户端获取用户信息
return R.ok(loginService.wxLogin(openid));
}
3.2 用户服务远程接口
在ruoyi-api模块中定义Feign客户端:
@FeignClient(
value = "ruoyi-system",
contextId = "remoteUserService",
fallbackFactory = RemoteUserFallbackFactory.class
)
public interface RemoteUserService {
@GetMapping("/user/info/{openid}")
R<LoginUser> getUserInfo(@PathVariable("openid") String openid,
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
@PostMapping("/user/wxuser")
R<Boolean> saveWxUser(@RequestBody SysUser user,
@RequestHeader(SecurityConstants.FROM_SOURCE) String source);
}
对应的服务端实现需要特别注意安全校验:
@RestController
public class SysUserController {
@InnerAuth
@GetMapping("/info/{openid}")
public R<LoginUser> getUserInfo(@PathVariable String openid) {
// 验证请求来源
if (!SecurityUtils.isInnerRequest()) {
throw new ServiceException("非法访问");
}
SysUser user = userService.selectUserByOpenid(openid);
if (user == null) {
return R.ok(new LoginUser());
}
// 构建登录用户信息
LoginUser loginUser = new LoginUser();
BeanUtils.copyProperties(user, loginUser);
return R.ok(loginUser);
}
}
4. 安全增强与性能优化
4.1 接口防刷策略
在认证中心添加限流保护:
@RateLimiter(time = 60, count = 30)
@PostMapping("/wxlogin")
public R<LoginUser> wxLogin(@Valid @RequestBody WxLoginForm form) {
// ...原有逻辑
}
配置Redis计数器防止重复请求:
# application.yml
spring:
redis:
rate-limiter:
enabled: true
capacity: 50
replenish-rate: 10
4.2 缓存优化方案
对于高频访问的用户信息,建议采用多级缓存:
@Service
public class UserServiceImpl implements UserService {
@Cacheable(
value = "userCache",
key = "'openid:' + #openid",
unless = "#result == null"
)
@Override
public SysUser selectUserByOpenid(String openid) {
return userMapper.selectUserByOpenid(openid);
}
@CacheEvict(
value = "userCache",
key = "'openid:' + #user.openId"
)
@Override
public int insertWxUser(SysUser user) {
return userMapper.insertUser(user);
}
}
4.3 事务一致性保障
用户创建时需要保证多表操作的原子性:
@Transactional(rollbackFor = Exception.class)
@Override
public int registerWxUser(SysUser user) {
// 插入用户主表
int rows = userMapper.insertUser(user);
// 分配默认角色
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getUserId());
userRole.setRoleId(2L); // 默认角色ID
userRoleMapper.insertUserRole(userRole);
// 初始化用户岗位
SysUserPost userPost = new SysUserPost();
userPost.setUserId(user.getUserId());
userPost.setPostId(4L); // 默认岗位ID
userPostMapper.insertUserPost(userPost);
return rows;
}
5. 异常处理与监控
5.1 统一异常拦截
创建微信登录专属异常处理器:
@RestControllerAdvice
public class WxExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(WxExceptionHandler.class);
@ExceptionHandler(WxApiException.class)
public R<?> handleWxApiException(WxApiException e) {
log.error("微信接口调用异常: {}", e.getMessage(), e);
return R.fail(e.getMessage());
}
@ExceptionHandler(FeignException.class)
public R<?> handleFeignException(FeignException e) {
log.error("微服务调用异常: {}", e.contentUTF8(), e);
return R.fail("服务间通信失败");
}
}
5.2 埋点监控配置
在Spring Boot Actuator基础上增加自定义指标:
@Configuration
public class WxMetricsConfig {
@Bean
MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags(
"application", "ruoyi-auth",
"module", "wx-login"
);
}
@Bean
Counter wxLoginCounter(MeterRegistry registry) {
return Counter.builder("wx.login.requests")
.description("微信登录请求计数")
.tag("type", "total")
.register(registry);
}
}
在控制器中记录指标:
@Autowired
private Counter wxLoginCounter;
@PostMapping("/wxlogin")
public R<?> wxLogin(@RequestBody WxLoginForm form) {
wxLoginCounter.increment();
// ...业务逻辑
}
实际项目中我们发现,微信接口的响应延迟直接影响用户体验,建议在网关层对/auth/wxlogin接口设置单独的超时策略:
spring:
cloud:
gateway:
routes:
- id: auth-service
uri: lb://ruoyi-auth
predicates:
- Path=/auth/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
- name: StripPrefix=1
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
更多推荐
所有评论(0)