|
|
@@ -0,0 +1,94 @@
|
|
|
+package com.zsElectric.boot.security.provider;
|
|
|
+
|
|
|
+import cn.binarywang.wx.miniapp.api.WxMaService;
|
|
|
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.zsElectric.boot.security.model.SysUserDetails;
|
|
|
+import com.zsElectric.boot.security.model.UserAuthCredentials;
|
|
|
+import com.zsElectric.boot.security.model.WxMiniAppPhoneCodeAuthenticationToken;
|
|
|
+import com.zsElectric.boot.system.service.UserService;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import me.chanjar.weixin.common.error.WxErrorException;
|
|
|
+import org.springframework.security.authentication.AuthenticationProvider;
|
|
|
+import org.springframework.security.authentication.CredentialsExpiredException;
|
|
|
+import org.springframework.security.authentication.DisabledException;
|
|
|
+import org.springframework.security.core.Authentication;
|
|
|
+import org.springframework.security.core.AuthenticationException;
|
|
|
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 微信小程序手机号Code认证Provider(新版接口)
|
|
|
+ *
|
|
|
+ * @author Ray.Hao
|
|
|
+ * @since 2.0.0
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class WxMiniAppPhoneCodeAuthenticationProvider implements AuthenticationProvider {
|
|
|
+
|
|
|
+ private final UserService userService;
|
|
|
+ private final WxMaService wxMaService;
|
|
|
+
|
|
|
+ public WxMiniAppPhoneCodeAuthenticationProvider(UserService userService, WxMaService wxMaService) {
|
|
|
+ this.userService = userService;
|
|
|
+ this.wxMaService = wxMaService;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
|
|
+ WxMiniAppPhoneCodeAuthenticationToken authenticationToken = (WxMiniAppPhoneCodeAuthenticationToken) authentication;
|
|
|
+ String phoneCode = (String) authenticationToken.getPrincipal();
|
|
|
+
|
|
|
+ // 1. 通过phoneCode获取手机号信息(新版接口)
|
|
|
+ WxMaPhoneNumberInfo phoneNumberInfo;
|
|
|
+ try {
|
|
|
+ phoneNumberInfo = wxMaService.getUserService().getPhoneNoInfo(phoneCode);
|
|
|
+ } catch (WxErrorException e) {
|
|
|
+ log.error("获取微信手机号失败", e);
|
|
|
+ throw new CredentialsExpiredException("获取手机号失败,code无效或已过期");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (phoneNumberInfo == null || StrUtil.isBlank(phoneNumberInfo.getPhoneNumber())) {
|
|
|
+ throw new CredentialsExpiredException("获取手机号失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ String phoneNumber = phoneNumberInfo.getPhoneNumber();
|
|
|
+ log.info("通过code获取到手机号: {}", phoneNumber);
|
|
|
+
|
|
|
+ // 2. 根据手机号查询用户,不存在则创建新用户
|
|
|
+ UserAuthCredentials userAuthCredentials = userService.getAuthCredentialsByMobile(phoneNumber);
|
|
|
+
|
|
|
+ if (userAuthCredentials == null) {
|
|
|
+ // 用户不存在,注册新用户(仅手机号,不绑定openId)
|
|
|
+ boolean registered = userService.registerUserByMobileAndOpenId(phoneNumber, null);
|
|
|
+ if (!registered) {
|
|
|
+ throw new UsernameNotFoundException("用户注册失败");
|
|
|
+ }
|
|
|
+ // 重新获取用户信息
|
|
|
+ userAuthCredentials = userService.getAuthCredentialsByMobile(phoneNumber);
|
|
|
+
|
|
|
+ if (userAuthCredentials == null) {
|
|
|
+ throw new UsernameNotFoundException("用户注册失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 检查用户状态
|
|
|
+ if (ObjectUtil.notEqual(userAuthCredentials.getStatus(), 1)) {
|
|
|
+ throw new DisabledException("用户已被禁用");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 构建认证后的用户详情
|
|
|
+ SysUserDetails userDetails = new SysUserDetails(userAuthCredentials);
|
|
|
+
|
|
|
+ // 5. 创建已认证的Token
|
|
|
+ return WxMiniAppPhoneCodeAuthenticationToken.authenticated(
|
|
|
+ userDetails,
|
|
|
+ userDetails.getAuthorities()
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(Class<?> authentication) {
|
|
|
+ return WxMiniAppPhoneCodeAuthenticationToken.class.isAssignableFrom(authentication);
|
|
|
+ }
|
|
|
+}
|