From cacf02681bfdda7926379d37d58ad1a21e398e1a Mon Sep 17 00:00:00 2001 From: lrj <owen.stl@gmail.com> Date: 星期六, 04 十月 2025 19:08:12 +0800 Subject: [PATCH] fix(auth): 对无 Authorization 的 GraphQL 请求默认匿名放行到解析层,避免 400/403;公开查询仍优先识别后放行 --- backend/src/main/java/com/rongyichuang/auth/service/AuthService.java | 610 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 604 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/com/rongyichuang/auth/service/AuthService.java b/backend/src/main/java/com/rongyichuang/auth/service/AuthService.java index e691bb4..e9deed6 100644 --- a/backend/src/main/java/com/rongyichuang/auth/service/AuthService.java +++ b/backend/src/main/java/com/rongyichuang/auth/service/AuthService.java @@ -2,7 +2,15 @@ import com.rongyichuang.auth.dto.LoginRequest; import com.rongyichuang.auth.dto.LoginResponse; +import com.rongyichuang.auth.dto.PhoneDecryptResponse; +import com.rongyichuang.auth.dto.WxLoginRequest; +import com.rongyichuang.auth.dto.WxLoginResponse; +import com.rongyichuang.auth.entity.WxLoginRecord; import com.rongyichuang.auth.util.JwtUtil; +import com.rongyichuang.service.WechatApiService; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; import com.rongyichuang.employee.entity.Employee; import com.rongyichuang.employee.repository.EmployeeRepository; import com.rongyichuang.judge.entity.Judge; @@ -11,14 +19,24 @@ import com.rongyichuang.player.repository.PlayerRepository; import com.rongyichuang.user.entity.User; import com.rongyichuang.user.repository.UserRepository; +import com.rongyichuang.common.entity.Media; +import com.rongyichuang.common.repository.MediaRepository; +import com.rongyichuang.common.enums.MediaTargetType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Optional; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; +import com.fasterxml.jackson.databind.ObjectMapper; /** * 璁よ瘉鏈嶅姟绫� @@ -45,6 +63,18 @@ @Autowired private JwtUtil jwtUtil; + + @Autowired + private WxLoginRecordService wxLoginRecordService; + + @Autowired + private WechatApiService wechatApiService; + + @Autowired + private MediaRepository mediaRepository; + + @Value("${app.base-url}") + private String baseUrl; /** * 鐢ㄦ埛鐧诲綍 @@ -85,10 +115,10 @@ throw new BadCredentialsException("娌℃湁鏉冮檺"); } - // 6. 鐢熸垚JWT token + // 7. 鐢熸垚JWT token String token = jwtUtil.generateToken(user.getId(), user.getPhone()); - // 7. 纭畾涓昏瑙掕壊绫诲瀷锛堜紭鍏堢骇锛歟mployee > judge > player锛� + // 8. 纭畾涓昏瑙掕壊绫诲瀷锛堜紭鍏堢骇锛歟mployee > judge > player锛� String userType; if (employeeOpt.isPresent()) { userType = "employee"; @@ -98,7 +128,7 @@ userType = "player"; } - // 8. 鏋勫缓鐢ㄦ埛淇℃伅 + // 9. 鏋勫缓鐢ㄦ埛淇℃伅 LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo( user.getId(), user.getName(), @@ -106,7 +136,7 @@ userType ); - // 9. 璁剧疆鎵�鏈夊叧鑱旂殑瑙掕壊淇℃伅 + // 10. 璁剧疆鎵�鏈夊叧鑱旂殑瑙掕壊淇℃伅 if (employeeOpt.isPresent()) { Employee employee = employeeOpt.get(); userInfo.setEmployee(new LoginResponse.EmployeeInfo( @@ -138,8 +168,7 @@ player.getId(), player.getName(), player.getPhone(), - player.getDescription(), - player.getAuditState() + player.getDescription() )); if (employeeOpt.isEmpty() && judgeOpt.isEmpty()) { logger.info("瀛﹀憳鐧诲綍鎴愬姛锛孖D: {}, 濮撳悕: {}", player.getId(), player.getName()); @@ -148,4 +177,573 @@ return new LoginResponse(token, userInfo); } + + /** + * 寰俊鐧诲綍 + */ + public WxLoginResponse wxLogin(WxLoginRequest wxLoginRequest) throws JsonProcessingException, JsonMappingException { + logger.info("=== 寮�濮嬪井淇$櫥褰曟祦绋� ==="); + logger.info("鐧诲綍鏃堕棿: {}", java.time.LocalDateTime.now()); + logger.info("璇锋眰鍙傛暟璇︽儏:"); + logger.info("- code: {}", wxLoginRequest.getCode()); + logger.info("- code闀垮害: {}", wxLoginRequest.getCode() != null ? wxLoginRequest.getCode().length() : 0); + logger.info("- wxOpenid: {}", wxLoginRequest.getWxOpenid()); + logger.info("- wxUnionid: {}", wxLoginRequest.getWxUnionid()); + logger.info("- phone: {}", wxLoginRequest.getPhone()); + logger.info("- loginIp: {}", wxLoginRequest.getLoginIp()); + logger.info("- deviceInfo: {}", wxLoginRequest.getDeviceInfo()); + logger.info("- phoneAuthorized: {}", wxLoginRequest.getPhoneAuthorized()); + + // 1. 閫氳繃code璋冪敤寰俊API鑾峰彇openid鍜寀nionid + WechatApiService.WechatUserInfo wechatUserInfo = null; + if (wxLoginRequest.getCode() != null && !wxLoginRequest.getCode().trim().isEmpty()) { + logger.info("姝ラ1: 璋冪敤寰俊API鑾峰彇鐢ㄦ埛淇℃伅"); + logger.info("浣跨敤code: {}", wxLoginRequest.getCode()); + + try { + wechatUserInfo = wechatApiService.getWechatUserInfo(wxLoginRequest.getCode()); + + // 灏嗕粠寰俊API鑾峰彇鐨勪俊鎭缃埌璇锋眰瀵硅薄涓� + wxLoginRequest.setWxOpenid(wechatUserInfo.getOpenid()); + wxLoginRequest.setWxUnionid(wechatUserInfo.getUnionid()); + wxLoginRequest.setSessionKey(wechatUserInfo.getSessionKey()); + + logger.info("鉁� 浠庡井淇PI鑾峰彇鐢ㄦ埛淇℃伅鎴愬姛"); + logger.info("- openid: {}", wechatUserInfo.getOpenid()); + logger.info("- unionid: {}", wechatUserInfo.getUnionid()); + logger.info("- sessionKey闀垮害: {}", wechatUserInfo.getSessionKey() != null ? wechatUserInfo.getSessionKey().length() : 0); + + } catch (Exception e) { + logger.error("鉂� 璋冪敤寰俊API澶辫触"); + logger.error("寮傚父淇℃伅: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + throw e; + } + } else { + logger.warn("鈿狅笍 寰俊鐧诲綍code涓虹┖锛屽皢浣跨敤璇锋眰涓殑openid鍜寀nionid"); + logger.info("璇锋眰涓殑openid: {}", wxLoginRequest.getWxOpenid()); + logger.info("璇锋眰涓殑unionid: {}", wxLoginRequest.getWxUnionid()); + } + + User user = null; + boolean isNewUser = false; + + logger.info("姝ラ2: 鏌ユ壘鎴栧垱寤虹敤鎴�"); + + // 2. 棣栧厛灏濊瘯閫氳繃openid鏌ユ壘鐢ㄦ埛 + if (wxLoginRequest.getWxOpenid() != null && !wxLoginRequest.getWxOpenid().trim().isEmpty()) { + logger.info("灏濊瘯閫氳繃openid鏌ユ壘鐢ㄦ埛: {}", wxLoginRequest.getWxOpenid()); + + try { + Optional<User> userOpt = userRepository.findByWxOpenid(wxLoginRequest.getWxOpenid()); + if (userOpt.isPresent()) { + user = userOpt.get(); + logger.info("鉁� 閫氳繃openid鎵惧埌鐢ㄦ埛"); + logger.info("- 鐢ㄦ埛ID: {}", user.getId()); + logger.info("- 鐢ㄦ埛濮撳悕: {}", user.getName()); + logger.info("- 鐢ㄦ埛鎵嬫満鍙�: {}", user.getPhone()); + logger.info("- 鐢ㄦ埛unionid: {}", user.getWxUnionid()); + } else { + logger.info("鉂� 閫氳繃openid鏈壘鍒扮敤鎴�"); + } + } catch (Exception e) { + logger.error("鉂� 閫氳繃openid鏌ユ壘鐢ㄦ埛鏃跺彂鐢熷紓甯�: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } else { + logger.warn("鈿狅笍 openid涓虹┖锛岃烦杩噊penid鏌ユ壘"); + } + + // 3. 濡傛灉閫氳繃openid娌℃壘鍒帮紝灏濊瘯閫氳繃unionid鏌ユ壘 + if (user == null && wxLoginRequest.getWxUnionid() != null && !wxLoginRequest.getWxUnionid().trim().isEmpty()) { + logger.info("灏濊瘯閫氳繃unionid鏌ユ壘鐢ㄦ埛: {}", wxLoginRequest.getWxUnionid()); + + try { + Optional<User> userOpt = userRepository.findByWxUnionid(wxLoginRequest.getWxUnionid()); + if (userOpt.isPresent()) { + user = userOpt.get(); + logger.info("鉁� 閫氳繃unionid鎵惧埌鐢ㄦ埛"); + logger.info("- 鐢ㄦ埛ID: {}", user.getId()); + logger.info("- 鐢ㄦ埛濮撳悕: {}", user.getName()); + logger.info("- 鐢ㄦ埛鎵嬫満鍙�: {}", user.getPhone()); + logger.info("- 鐢ㄦ埛openid: {}", user.getWxOpenid()); + + // 鏇存柊鐢ㄦ埛鐨刼penid锛堝鏋滀箣鍓嶆病鏈夛級 + if (user.getWxOpenid() == null || user.getWxOpenid().trim().isEmpty()) { + logger.info("鐢ㄦ埛openid涓虹┖锛岄渶瑕佹洿鏂�"); + user.setWxOpenid(wxLoginRequest.getWxOpenid()); + try { + userRepository.save(user); + logger.info("鉁� 鎴愬姛鏇存柊鐢ㄦ埛openid锛岀敤鎴稩D: {}", user.getId()); + } catch (Exception e) { + logger.error("鉂� 鏇存柊鐢ㄦ埛openid澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } else { + logger.info("鐢ㄦ埛openid宸插瓨鍦紝鏃犻渶鏇存柊"); + } + } else { + logger.info("鉂� 閫氳繃unionid鏈壘鍒扮敤鎴�"); + } + } catch (Exception e) { + logger.error("鉂� 閫氳繃unionid鏌ユ壘鐢ㄦ埛鏃跺彂鐢熷紓甯�: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } else { + logger.warn("鈿狅笍 unionid涓虹┖鎴栫敤鎴峰凡鎵惧埌锛岃烦杩噓nionid鏌ユ壘"); + } + + // 4. 濡傛灉閮芥病鎵惧埌鐢ㄦ埛锛屼笉鍒涘缓鏂扮敤鎴凤紝鍙褰曠櫥褰曚俊鎭� + if (user == null) { + logger.info("鏈壘鍒扮幇鏈夌敤鎴凤紝鏅�氳闂敤鎴蜂笉鍒涘缓user璁板綍锛屽彧璁板綍鐧诲綍淇℃伅"); + logger.info("璁块棶鐢ㄦ埛淇℃伅:"); + logger.info("- openid: {}", wxLoginRequest.getWxOpenid()); + logger.info("- unionid: {}", wxLoginRequest.getWxUnionid()); + logger.info("- phone: {}", wxLoginRequest.getPhone()); + + // 璁板綍鐧诲綍淇℃伅鍒皌_login_record锛屼絾涓嶅垱寤虹敤鎴� + logger.info("姝ラ3: 璁板綍璁块棶鐢ㄦ埛鐨勭櫥褰曚俊鎭�"); + WxLoginRecord loginRecord = null; + try { + loginRecord = wxLoginRecordService.createLoginRecord( + wxLoginRequest.getWxOpenid(), + wxLoginRequest.getWxUnionid(), + null, // 娌℃湁鐢ㄦ埛ID + wxLoginRequest.getLoginIp(), + wxLoginRequest.getDeviceInfo(), + wxLoginRequest.getSessionKey(), + wxLoginRequest.getPhoneAuthorized() + ); + logger.info("鉁� 鎴愬姛鍒涘缓璁块棶鐢ㄦ埛鐧诲綍璁板綍锛岃褰旾D: {}", loginRecord.getId()); + } catch (Exception e) { + logger.error("鉂� 鍒涘缓鐧诲綍璁板綍澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + throw new RuntimeException("鍒涘缓鐧诲綍璁板綍澶辫触: " + e.getMessage(), e); + } + + // 杩斿洖璁块棶鐢ㄦ埛鐨勫搷搴旓紙鏃犵敤鎴蜂俊鎭紝鏃爐oken锛� + WxLoginResponse response = new WxLoginResponse(); + response.setSuccess(true); + response.setMessage("璁块棶鎴愬姛"); + response.setSessionKey(wxLoginRequest.getSessionKey()); + response.setIsNewUser(false); + response.setHasEmployee(false); + response.setHasJudge(false); + response.setHasPlayer(false); + + logger.info("=== 寰俊璁块棶娴佺▼瀹屾垚锛堟棤鐢ㄦ埛鍒涘缓锛� ==="); + return response; + } + + // 5. 璁板綍鐧诲綍淇℃伅鍒版柊琛� + logger.info("姝ラ3: 璁板綍鐧诲綍淇℃伅"); + WxLoginRecord loginRecord = null; + try { + loginRecord = wxLoginRecordService.createLoginRecord( + wxLoginRequest.getWxOpenid(), + wxLoginRequest.getWxUnionid(), + user.getId(), + wxLoginRequest.getLoginIp(), + wxLoginRequest.getDeviceInfo(), + wxLoginRequest.getSessionKey(), + wxLoginRequest.getPhoneAuthorized() + ); + logger.info("鉁� 鎴愬姛鍒涘缓鐧诲綍璁板綍锛岃褰旾D: {}", loginRecord.getId()); + } catch (Exception e) { + logger.error("鉂� 鍒涘缓鐧诲綍璁板綍澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + throw new RuntimeException("鍒涘缓鐧诲綍璁板綍澶辫触: " + e.getMessage(), e); + } + + // 6. 鏌ユ壘鍏宠仈鐨勫憳宸ャ�佽瘎濮斿拰瀛﹀憳淇℃伅 + logger.info("姝ラ4: 鏌ユ壘鐢ㄦ埛鍏宠仈鐨勮鑹蹭俊鎭�"); + logger.info("鏌ユ壘鐢ㄦ埛ID: {}", user.getId()); + + Optional<Employee> employeeOpt = Optional.empty(); + Optional<Judge> judgeOpt = Optional.empty(); + Optional<Player> playerOpt = Optional.empty(); + + try { + employeeOpt = employeeRepository.findByUserId(user.getId()); + logger.info("鍛樺伐瑙掕壊鏌ユ壘缁撴灉: {}", employeeOpt.isPresent() ? "鎵惧埌" : "鏈壘鍒�"); + if (employeeOpt.isPresent()) { + Employee employee = employeeOpt.get(); + logger.info("- 鍛樺伐ID: {}", employee.getId()); + logger.info("- 鍛樺伐濮撳悕: {}", employee.getName()); + logger.info("- 鍛樺伐瑙掕壊ID: {}", employee.getRoleId()); + } + } catch (Exception e) { + logger.error("鉂� 鏌ユ壘鍛樺伐瑙掕壊鏃跺彂鐢熷紓甯�: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + + try { + judgeOpt = judgeRepository.findByUserId(user.getId()); + logger.info("璇勫瑙掕壊鏌ユ壘缁撴灉: {}", judgeOpt.isPresent() ? "鎵惧埌" : "鏈壘鍒�"); + if (judgeOpt.isPresent()) { + Judge judge = judgeOpt.get(); + logger.info("- 璇勫ID: {}", judge.getId()); + logger.info("- 璇勫濮撳悕: {}", judge.getName()); + logger.info("- 璇勫鑱岀О: {}", judge.getTitle()); + logger.info("- 璇勫鍏徃: {}", judge.getCompany()); + } + } catch (Exception e) { + logger.error("鉂� 鏌ユ壘璇勫瑙掕壊鏃跺彂鐢熷紓甯�: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + + try { + playerOpt = playerRepository.findByUserId(user.getId()); + logger.info("瀛﹀憳瑙掕壊鏌ユ壘缁撴灉: {}", playerOpt.isPresent() ? "鎵惧埌" : "鏈壘鍒�"); + if (playerOpt.isPresent()) { + Player player = playerOpt.get(); + logger.info("- 瀛﹀憳ID: {}", player.getId()); + logger.info("- 瀛﹀憳濮撳悕: {}", player.getName()); + logger.info("- 瀛﹀憳鎵嬫満鍙�: {}", player.getPhone()); + } + } catch (Exception e) { + logger.error("鉂� 鏌ユ壘瀛﹀憳瑙掕壊鏃跺彂鐢熷紓甯�: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + + // 6. 鐢熸垚JWT token + logger.info("姝ラ5: 鐢熸垚JWT token"); + String tokenIdentifier = user.getPhone() != null ? user.getPhone() : user.getWxOpenid(); + logger.info("Token鏍囪瘑绗�: {}", tokenIdentifier); + + String token = null; + try { + token = jwtUtil.generateToken(user.getId(), tokenIdentifier); + logger.info("鉁� 鎴愬姛鐢熸垚JWT token锛岄暱搴�: {}", token != null ? token.length() : 0); + } catch (Exception e) { + logger.error("鉂� 鐢熸垚JWT token澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + throw new RuntimeException("鐢熸垚JWT token澶辫触: " + e.getMessage(), e); + } + + // 7. 纭畾涓昏瑙掕壊绫诲瀷锛堜紭鍏堢骇锛歟mployee > judge > player锛� + logger.info("姝ラ6: 纭畾鐢ㄦ埛涓昏瑙掕壊绫诲瀷"); + String userType; + if (employeeOpt.isPresent()) { + userType = "employee"; + logger.info("鐢ㄦ埛涓昏瑙掕壊: 鍛樺伐"); + } else if (judgeOpt.isPresent()) { + userType = "judge"; + logger.info("鐢ㄦ埛涓昏瑙掕壊: 璇勫"); + } else if (playerOpt.isPresent()) { + userType = "player"; + logger.info("鐢ㄦ埛涓昏瑙掕壊: 瀛﹀憳"); + } else { + userType = "user"; // 鏅�氬井淇$敤鎴� + logger.info("鐢ㄦ埛涓昏瑙掕壊: 鏅�氬井淇$敤鎴�"); + } + + // 8. 鏋勫缓鐢ㄦ埛淇℃伅 + logger.info("姝ラ7: 鏋勫缓鐢ㄦ埛淇℃伅鍝嶅簲"); + LoginResponse.UserInfo userInfo = null; + try { + userInfo = new LoginResponse.UserInfo( + user.getId(), + user.getName(), + user.getPhone(), + userType + ); + logger.info("鉁� 鎴愬姛鏋勫缓鍩虹鐢ㄦ埛淇℃伅"); + logger.info("- 鐢ㄦ埛ID: {}", user.getId()); + logger.info("- 鐢ㄦ埛濮撳悕: {}", user.getName()); + logger.info("- 鐢ㄦ埛鎵嬫満鍙�: {}", user.getPhone()); + logger.info("- 鐢ㄦ埛绫诲瀷: {}", userType); + } catch (Exception e) { + logger.error("鉂� 鏋勫缓鍩虹鐢ㄦ埛淇℃伅澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + throw new RuntimeException("鏋勫缓鍩虹鐢ㄦ埛淇℃伅澶辫触: " + e.getMessage(), e); + } + + // 9. 鑾峰彇骞惰缃敤鎴峰ご鍍� + logger.info("姝ラ8: 鑾峰彇鐢ㄦ埛澶村儚"); + try { + List<Media> avatarMediaList = mediaRepository.findByTargetTypeAndTargetIdAndState( + MediaTargetType.USER_AVATAR.getValue(), + user.getId(), + 1 + ); + if (!avatarMediaList.isEmpty()) { + Media avatarMedia = avatarMediaList.get(0); + String fullAvatarUrl = buildFullMediaUrl(avatarMedia.getPath()); + userInfo.setAvatarUrl(fullAvatarUrl); + logger.info("鉁� 鎵惧埌鐢ㄦ埛澶村儚: {} -> {}", avatarMedia.getPath(), fullAvatarUrl); + } else { + logger.info("鐢ㄦ埛{}娌℃湁鎵惧埌澶村儚", user.getId()); + } + } catch (Exception e) { + logger.error("鉂� 鑾峰彇鐢ㄦ埛澶村儚澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + + // 10. 璁剧疆鎵�鏈夊叧鑱旂殑瑙掕壊淇℃伅 + logger.info("姝ラ9: 璁剧疆瑙掕壊璇︾粏淇℃伅"); + + if (employeeOpt.isPresent()) { + try { + Employee employee = employeeOpt.get(); + userInfo.setEmployee(new LoginResponse.EmployeeInfo( + employee.getId(), + employee.getName(), + employee.getRoleId(), + employee.getDescription() + )); + logger.info("鉁� 璁剧疆鍛樺伐淇℃伅鎴愬姛"); + logger.info("- 鍛樺伐ID: {}", employee.getId()); + logger.info("- 鍛樺伐濮撳悕: {}", employee.getName()); + logger.info("- 鍛樺伐瑙掕壊ID: {}", employee.getRoleId()); + logger.info("鍛樺伐寰俊鐧诲綍鎴愬姛锛孖D: {}, 濮撳悕: {}", employee.getId(), employee.getName()); + } catch (Exception e) { + logger.error("鉂� 璁剧疆鍛樺伐淇℃伅澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } + + if (judgeOpt.isPresent()) { + try { + Judge judge = judgeOpt.get(); + userInfo.setJudge(new LoginResponse.JudgeInfo( + judge.getId(), + judge.getName(), + judge.getTitle(), + judge.getCompany(), + judge.getDescription() + )); + logger.info("鉁� 璁剧疆璇勫淇℃伅鎴愬姛"); + logger.info("- 璇勫ID: {}", judge.getId()); + logger.info("- 璇勫濮撳悕: {}", judge.getName()); + logger.info("- 璇勫鑱岀О: {}", judge.getTitle()); + logger.info("- 璇勫鍏徃: {}", judge.getCompany()); + + if (employeeOpt.isEmpty()) { + logger.info("璇勫寰俊鐧诲綍鎴愬姛锛孖D: {}, 濮撳悕: {}", judge.getId(), judge.getName()); + } + } catch (Exception e) { + logger.error("鉂� 璁剧疆璇勫淇℃伅澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } + + if (playerOpt.isPresent()) { + try { + Player player = playerOpt.get(); + userInfo.setPlayer(new LoginResponse.PlayerInfo( + player.getId(), + player.getName(), + player.getPhone(), + player.getDescription() + )); + logger.info("鉁� 璁剧疆瀛﹀憳淇℃伅鎴愬姛"); + logger.info("- 瀛﹀憳ID: {}", player.getId()); + logger.info("- 瀛﹀憳濮撳悕: {}", player.getName()); + logger.info("- 瀛﹀憳鎵嬫満鍙�: {}", player.getPhone()); + + if (employeeOpt.isEmpty() && judgeOpt.isEmpty()) { + logger.info("瀛﹀憳寰俊鐧诲綍鎴愬姛锛孖D: {}, 濮撳悕: {}", player.getId(), player.getName()); + } + } catch (Exception e) { + logger.error("鉂� 璁剧疆瀛﹀憳淇℃伅澶辫触: {}", e.getMessage()); + logger.error("寮傚父鍫嗘爤:", e); + } + } + + logger.info("=== 寰俊鐧诲綍娴佺▼瀹屾垚 ==="); + logger.info("鐧诲綍缁撴灉:"); + logger.info("- 鏄惁鏂扮敤鎴�: {}", isNewUser); + logger.info("- 鐧诲綍璁板綍ID: {}", loginRecord != null ? loginRecord.getId() : "null"); + logger.info("- Token闀垮害: {}", token != null ? token.length() : 0); + logger.info("- 鐢ㄦ埛绫诲瀷: {}", userType); + logger.info("瀹屾垚鏃堕棿: {}", java.time.LocalDateTime.now()); + + return new WxLoginResponse(token, userInfo, isNewUser, loginRecord.getId(), wxLoginRequest.getSessionKey()); + } + + /** + * 鏋勫缓瀹屾暣鐨勫獟浣揢RL + * @param path 濯掍綋璺緞 + * @return 瀹屾暣鐨刄RL + */ + private String buildFullMediaUrl(String path) { + if (path == null || path.trim().isEmpty()) { + return null; + } + + // 濡傛灉璺緞宸茬粡鏄畬鏁碪RL锛岀洿鎺ヨ繑鍥� + if (path.startsWith("http://") || path.startsWith("https://")) { + return path; + } + + // 鏋勫缓瀹屾暣URL + String cleanBaseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl; + String cleanPath = path.startsWith("/") ? path : "/" + path; + return cleanBaseUrl + cleanPath; + } + + /** + * 瑙e瘑寰俊鎵嬫満鍙� + */ + public PhoneDecryptResponse decryptPhoneNumber(String encryptedData, String iv, String sessionKey) { + logger.info("=== 寮�濮嬭В瀵嗗井淇℃墜鏈哄彿 ==="); + logger.info("瑙e瘑鏃堕棿: {}", java.time.LocalDateTime.now()); + logger.info("encryptedData闀垮害: {}", encryptedData != null ? encryptedData.length() : 0); + logger.info("iv闀垮害: {}", iv != null ? iv.length() : 0); + logger.info("sessionKey闀垮害: {}", sessionKey != null ? sessionKey.length() : 0); + + try { + // 1. Base64瑙g爜 + byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData); + byte[] ivBytes = Base64.getDecoder().decode(iv); + byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey); + + logger.info("Base64瑙g爜鎴愬姛"); + logger.info("encryptedBytes闀垮害: {}", encryptedBytes.length); + logger.info("ivBytes闀垮害: {}", ivBytes.length); + logger.info("sessionKeyBytes闀垮害: {}", sessionKeyBytes.length); + + // 2. AES瑙e瘑 + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec secretKeySpec = new SecretKeySpec(sessionKeyBytes, "AES"); + IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); + + byte[] decryptedBytes = cipher.doFinal(encryptedBytes); + String decryptedData = new String(decryptedBytes, "UTF-8"); + + logger.info("AES瑙e瘑鎴愬姛"); + logger.info("瑙e瘑鍚庢暟鎹暱搴�: {}", decryptedData.length()); + logger.info("瑙e瘑鍚庢暟鎹�: {}", decryptedData); + + // 3. 瑙f瀽JSON + ObjectMapper objectMapper = new ObjectMapper(); + WechatPhoneInfo phoneInfo = objectMapper.readValue(decryptedData, WechatPhoneInfo.class); + + logger.info("JSON瑙f瀽鎴愬姛"); + logger.info("鎵嬫満鍙�: {}", phoneInfo.getPhoneNumber()); + logger.info("绾墜鏈哄彿: {}", phoneInfo.getPurePhoneNumber()); + logger.info("鍥藉浠g爜: {}", phoneInfo.getCountryCode()); + + PhoneDecryptResponse response = new PhoneDecryptResponse( + phoneInfo.getPhoneNumber(), + phoneInfo.getPurePhoneNumber(), + phoneInfo.getCountryCode() + ); + + logger.info("鉁� 寰俊鎵嬫満鍙疯В瀵嗘垚鍔�"); + return response; + + } catch (Exception e) { + logger.error("鉂� 寰俊鎵嬫満鍙疯В瀵嗗け璐�", e); + String friendlyMessage = getDecryptFriendlyErrorMessage(e); + throw new RuntimeException(friendlyMessage, e); + } + } + + /** + * 浣跨敤鏂扮増API閫氳繃code鐩存帴鑾峰彇鎵嬫満鍙� + */ + public PhoneDecryptResponse getPhoneNumberByCode(String code) { + logger.info("=== 寮�濮嬩娇鐢ㄦ柊鐗圓PI鑾峰彇鎵嬫満鍙� ==="); + logger.info("鑾峰彇鏃堕棿: {}", java.time.LocalDateTime.now()); + logger.info("杈撳叆code: {}", code); + + try { + // 璋冪敤寰俊API鏈嶅姟鑾峰彇鎵嬫満鍙� + WechatApiService.WechatPhoneInfo phoneInfo = wechatApiService.getPhoneNumberByCode(code); + + logger.info("鉁� 鏂扮増API鑾峰彇鎵嬫満鍙锋垚鍔�"); + logger.info("鎵嬫満鍙�: {}", phoneInfo.getPhoneNumber()); + logger.info("绾墜鏈哄彿: {}", phoneInfo.getPurePhoneNumber()); + logger.info("鍥藉浠g爜: {}", phoneInfo.getCountryCode()); + + PhoneDecryptResponse response = new PhoneDecryptResponse( + phoneInfo.getPhoneNumber(), + phoneInfo.getPurePhoneNumber(), + phoneInfo.getCountryCode() + ); + + return response; + + } catch (Exception e) { + logger.error("鉂� 鏂扮増API鑾峰彇鎵嬫満鍙峰け璐�", e); + // 鐩存帴浼犻�扺echatApiService鐨勫弸濂介敊璇俊鎭� + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * 寰俊鎵嬫満鍙蜂俊鎭� + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class WechatPhoneInfo { + private String phoneNumber; + private String purePhoneNumber; + private String countryCode; + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + public String getPurePhoneNumber() { + return purePhoneNumber; + } + + public void setPurePhoneNumber(String purePhoneNumber) { + this.purePhoneNumber = purePhoneNumber; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + } + + /** + * 鏍规嵁瑙e瘑寮傚父鎻愪緵鍙嬪ソ鐨勯敊璇俊鎭� + */ + private String getDecryptFriendlyErrorMessage(Exception e) { + String errorMessage = e.getMessage(); + + if (e instanceof IllegalArgumentException) { + if (errorMessage.contains("Illegal base64 character")) { + return "鎺堟潈鏁版嵁鏍煎紡閿欒锛岃閲嶆柊鑾峰彇鎵嬫満鍙锋巿鏉�"; + } + } + + if (e instanceof javax.crypto.BadPaddingException) { + return "鎺堟潈鏁版嵁宸茶繃鏈熸垨鏃犳晥锛岃閲嶆柊鑾峰彇鎵嬫満鍙锋巿鏉�"; + } + + if (e instanceof javax.crypto.IllegalBlockSizeException) { + return "鎺堟潈鏁版嵁闀垮害閿欒锛岃閲嶆柊鑾峰彇鎵嬫満鍙锋巿鏉�"; + } + + if (e instanceof java.security.InvalidKeyException) { + return "浼氳瘽瀵嗛挜鏃犳晥锛岃閲嶆柊鐧诲綍鍚庡啀璇�"; + } + + if (e instanceof com.fasterxml.jackson.core.JsonParseException) { + return "鎺堟潈鏁版嵁瑙f瀽澶辫触锛岃閲嶆柊鑾峰彇鎵嬫満鍙锋巿鏉�"; + } + + if (errorMessage.contains("sessionKey")) { + return "浼氳瘽宸茶繃鏈燂紝璇烽噸鏂扮櫥褰曞悗鍐嶈瘯"; + } + + if (errorMessage.contains("encryptedData")) { + return "鎺堟潈鏁版嵁鏃犳晥锛岃閲嶆柊鑾峰彇鎵嬫満鍙锋巿鏉�"; + } + + return "鎵嬫満鍙疯В瀵嗗け璐ワ紝璇烽噸鏂拌幏鍙栨墜鏈哄彿鎺堟潈"; + } } \ No newline at end of file -- Gitblit v1.8.0