refactor: 移除/mscode命令,正版验证全部交web后端接管

- 移除/mscode命令(plugin.yml + onCommand + executor注册)
- 移除extractCodeFromInput()方法(仅/mscode使用)
- 移除verifyMinecraftAuthCode()方法(仅/mscode使用)
- Java端仅负责:创建session → 轮询PHP状态 → 自动登录
- 所有授权码输入由PHP粘贴页全权处理(自动提交)
- 解决MC聊天框256字符硬限导致URL截断的根本问题
This commit is contained in:
2026-07-17 20:55:31 +08:00
parent f5a3dfbda5
commit c79924f67d
3 changed files with 4 additions and 171 deletions
+1 -82
View File
@@ -457,8 +457,6 @@ public class Main extends JavaPlugin
getCommand("mslogin").setExecutor(this);
if (getCommand("正版") != null)
getCommand("正版").setExecutor(this);
if (getCommand("mscode") != null)
getCommand("mscode").setExecutor(this);
if (getCommand("签到") != null)
getCommand("签到")
.setExecutor(this);
@@ -1601,52 +1599,7 @@ public class Main extends JavaPlugin
hideInventory(p);
}
// ===== Microsoft OAuth正版验证 =====
/**
* 从用户输入中提取Microsoft OAuth授权码
* 支持:纯授权码、完整URL(含code=参数)
*/
private String extractCodeFromInput(String input) {
if (input == null || input.isEmpty()) return null;
input = input.trim();
// 如果包含code=参数,从中提取
if (input.contains("code=") || input.startsWith("http") || input.contains("#")) {
try {
// ★ 优先处理 #code= fragment形式(Microsoft公共客户端OAuth返回格式)
// URL如: https://login.live.com/oauth20_desktop.srf#code=M.C512_BAY.2_xxx
if (input.contains("#code=")) {
int hashIdx = input.indexOf("#code=");
String afterHash = input.substring(hashIdx + 6); // "#code=" 之后的内容
// code到下一个&或字符串结尾
int ampIdx = afterHash.indexOf('&');
String rawCode = ampIdx >= 0 ? afterHash.substring(0, ampIdx) : afterHash;
return java.net.URLDecoder.decode(rawCode, StandardCharsets.UTF_8);
}
// 尝试解析URL中的query参数 (?code=xxx)
int qIdx = input.indexOf('?');
if (qIdx >= 0) {
String query = input.substring(qIdx + 1);
// 去掉fragment部分
int hashQIdx = query.indexOf('#');
if (hashQIdx >= 0) query = query.substring(0, hashQIdx);
for (String param : query.split("&")) {
String[] kv = param.split("=", 2);
if (kv.length == 2 && kv[0].equals("code")) {
return java.net.URLDecoder.decode(kv[1], StandardCharsets.UTF_8);
}
}
}
} catch (Exception e) {
getLogger().warning("[正版验证] extractCodeFromInput解析异常: " + e.getMessage());
}
}
// 直接作为授权码返回(纯code)
return input;
}
// ===== Microsoft OAuth正版验证(Java仅开session+轮询,所有输入交web后端) =====
/**
* 处理正版验证命令:调用PHP后端获取授权URL,显示给玩家,启动轮询
@@ -6056,40 +6009,6 @@ public class Main extends JavaPlugin
return true;
}
// ===== /mscode <授权码或URL>:粘贴Microsoft OAuth授权码或完整URL =====
if (cmdName.equals("mscode")) {
if (!(sender instanceof Player)) {
sender.sendMessage("§c仅玩家可用");
return true;
}
Player p = (Player) sender;
if (loggedIn.contains(p.getName())) {
p.sendMessage("§c您已登录,无需重复验证");
return true;
}
if (args.length < 1) {
p.sendMessage("§c用法: /mscode <授权码或完整URL>");
p.sendMessage("§7粘贴Microsoft登录后的授权码,或粘贴包含code=的完整URL");
return true;
}
String rawInput = String.join(" ", args).trim();
// 自动从URL中提取code参数
String code = extractCodeFromInput(rawInput);
if (code == null || code.length() < 10) {
p.sendMessage("§c无法从输入中提取有效的授权码");
p.sendMessage("§7请粘贴授权码或包含code=的完整URL");
return true;
}
// 检查是否有进行中的会话
if (webManager == null || !webManager.isMinecraftAuthPending(p.getName())) {
p.sendMessage("§c您没有进行中的验证会话,请先执行 /mslogin 发起验证");
return true;
}
p.sendMessage("§e正在提交授权码验证...");
webManager.verifyMinecraftAuthCode(p, code);
return true;
}
// /找回密码
if (cmdName.equals("找回密码")) {
if (!(sender instanceof Player)) {
+3 -86
View File
@@ -4984,9 +4984,9 @@ public class WebManager {
Bukkit.getScheduler().runTask(plugin, () -> {
if (player.isOnline()) {
player.sendMessage("§6§l===== 正版验证 =====");
player.sendMessage("§7方式一: 点击下方链接打开粘贴页面");
player.sendMessage("§7方式二: /mscode <粘贴完整URL或授权码>");
player.sendMessage("§7步骤: 打开链接 → 登录 → 复制地址栏URL → 粘贴");
player.sendMessage("§7点击下方链接打开粘贴页面");
player.sendMessage("§7步骤: 点击登录 → 登录微软 → 复制地址栏URL → 粘贴到页面");
player.sendMessage("§7粘贴URL后会自动提交验证");
player.sendMessage("§7链接10分钟内有效");
player.sendMessage("§6§l====================");
// 尝试发送可点击的URL(授权链接)
@@ -5149,89 +5149,6 @@ public class WebManager {
minecraftAuthSessions.remove(playerName);
}
/**
* 验证玩家粘贴的Microsoft OAuth授权码(/mscode命令调用)
* 将授权码发送给PHP后端的verify_code端点
*/
public void verifyMinecraftAuthCode(Player player, String code) {
String playerName = player.getName();
String[] sessionData = minecraftAuthSessions.get(playerName);
if (sessionData == null) {
player.sendMessage("§c没有找到您的验证会话,请先执行 /mslogin");
return;
}
String sessionId = sessionData[0];
String secret = secretKey; // ★ 不再URLEncoder.encode,直接发送原始密钥
// ★ 调试日志:记录code提取结果
plugin.getLogger().info("[正版验证] /mscode 提交 - 玩家: " + playerName);
plugin.getLogger().info("[正版验证] sessionId: " + sessionId);
plugin.getLogger().info("[正版验证] code(前80字符): " + code.substring(0, Math.min(80, code.length())));
plugin.getLogger().info("[正版验证] code长度: " + code.length());
plugin.getLogger().info("[正版验证] secret: " + secret);
webExecutor.submit(() -> {
try {
String url = webBaseUrl + "/api/minecraft_auth.php?action=verify_code";
// POST参数(JSON格式,与doPost的Content-Type一致)
com.google.gson.JsonObject postData = new com.google.gson.JsonObject();
postData.addProperty("session_id", sessionId);
postData.addProperty("code", code);
postData.addProperty("secret", secret);
String postBody = postData.toString();
plugin.getLogger().info("[正版验证] POST body(前200字符): " + postBody.substring(0, Math.min(200, postBody.length())));
String response = doPost(url, postBody);
if (response == null) {
player.sendMessage("§c无法连接Web后端");
return;
}
com.google.gson.JsonObject json;
try {
json = com.google.gson.JsonParser.parseString(response).getAsJsonObject();
} catch (Exception parseEx) {
String preview = response.length() > 150 ? response.substring(0, 150) + "..." : response;
player.sendMessage("§c后端返回异常: " + preview);
plugin.getLogger().warning("[正版验证] verify_code返回非JSON: " + preview);
return;
}
if (json.get("success").getAsBoolean()) {
com.google.gson.JsonObject data = json.getAsJsonObject("data");
String mcUuid = data.get("mc_uuid").getAsString();
String mcUsername = data.get("mc_username").getAsString();
plugin.getLogger().info("[正版验证] 粘贴码验证成功: " + playerName + " -> " + mcUsername + " (" + mcUuid + ")");
// 记录为已验证正版玩家
plugin.addVerifiedPremiumPlayer(playerName, mcUuid, mcUsername);
// 清理会话
minecraftAuthSessions.remove(playerName);
BukkitRunnable poller = minecraftAuthPollers.remove(playerName);
if (poller != null) poller.cancel();
// 在主线程执行自动登录
Bukkit.getScheduler().runTask(plugin, () -> {
if (player.isOnline() && !plugin.getLoggedIn().contains(playerName)) {
player.sendMessage("§a§l正版验证成功!欢迎 " + mcUsername + "!");
plugin.autoLogin(player, "premium");
}
});
} else {
String error = json.has("error") ? json.get("error").getAsString() : "验证失败";
player.sendMessage("§c" + error);
}
} catch (Exception e) {
plugin.getLogger().warning("[正版验证] 粘贴码验证异常: " + e.getMessage());
player.sendMessage("§c验证请求失败,请稍后重试");
}
});
}
/**
* 同步在线玩家列表到PHP端(用于Web登录状态检查)
* 注意:推送所有在线玩家(包括未登录的),PHP端通过 web_login_verified 判断是否已认证
-3
View File
@@ -123,9 +123,6 @@ commands:
正版:
description: 正版登录(中文版)
usage: /正版
mscode:
description: 粘贴Microsoft OAuth授权码
usage: /mscode <授权码>
tpa:
description: tp传送指令
usage: /tpa