├── .gitignore ├── README.md ├── TPCraftIDACAuth.iml ├── pom.xml └── src └── main ├── java └── net │ └── tpcraft │ └── minecraft │ ├── Config.java │ ├── TPCraftIDACAuth.java │ ├── command │ ├── MainCommand.java │ └── MainTabCompleter.java │ ├── event │ ├── JoinEvent.java │ ├── LeaveEvent.java │ └── MainEvent.java │ ├── server │ └── http │ │ ├── WebServer.java │ │ └── controller │ │ └── Oauth2Controller.java │ └── util │ ├── HTTPRequest.java │ ├── MapList.java │ └── Moment.java └── resources ├── config.yml ├── data └── autoLoginData.yml ├── plugin.yml └── template └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | 3 | /target/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 警告 2 | 该项目已经弃坑,对于Minecraft Java服务器授权,我们已经使用YggdrasilAPI外置登录,详情请查看:[https://wiki.tpcraft.net/zh/TPCraftAPI/YggdrasilAPI](https://wiki.tpcraft.net/zh/TPCraftAPI/YggdrasilAPI)。 3 | 4 | ## TPCraftIDAC Auth 5 | 6 | TPCraft身份认证中心授权,适用于Minecraft Java服务器,玩家通过TPCraft身份认证中心登入到服务器 7 | 8 | ## 相关文档 9 | 10 | [https://tpcraft-1.gitbook.io/oauth2](https://tpcraft-1.gitbook.io/oauth2) 11 | 12 | ## 版本兼容 13 | 14 | 全版本兼容 15 | 16 | ## 功能 17 | 18 | - 基础授权 19 | - 自定义登入消息 20 | - 自动登入 21 | - 固定登入坐标 22 | - 白名单 23 | - (敬请期待)... 24 | 25 | ## 命令 26 | 27 | | 命令 | 描述 | 权限 | 28 | |-------------------------------|------------|------------| 29 | | /auth | 主命令 | | 30 | | /auth loginMessage on | 启用登入消息 | auth.admin | 31 | | /auth loginMessage off | 禁用登入消息 | auth.admin | 32 | | /auth autoLogin on | 启用自动登入 | auth.admin | 33 | | /auth autoLogin off | 禁用自动登入 | auth.admin | 34 | | /auth autoLogin set <超时时间(秒)> | 设置自动登入超时时间 | auth.admin | 35 | | /auth loginPosition on | 启用固定登入坐标 | auth.admin | 36 | | /auth loginPosition off | 禁用固定登入坐标 | auth.admin | 37 | | /auth loginPosition set | 设置固定登入坐标 | auth.admin | 38 | | /auth whiteList on | 启用白名单 | auth.admin | 39 | | /auth whiteList off | 禁用白名单 | auth.admin | 40 | | /auth whiteList add <玩家名称> | 添加白名单 | auth.admin | 41 | | /auth whiteList remove <玩家名称> | 移除白名单 | auth.admin | 42 | | /auth whiteList list | 白名单列表 | auth.admin | 43 | | /auth reload | 重载插件 | auth.admin | 44 | 45 | ## 配置文件 46 | 47 | ``` yml 48 | ######################################################################################## 49 | # __________ ______ ______ ________ ___ ______ ___ __ __ # 50 | # /_ __/ __ \/ ____/________ _/ __/ /_/ _/ __ \/ | / ____/ / | __ __/ /_/ /_ # 51 | # / / / /_/ / / / ___/ __ `/ /_/ __// // / / / /| |/ / / /| |/ / / / __/ __ \ # 52 | # / / / ____/ /___/ / / /_/ / __/ /__/ // /_/ / ___ / /___ / ___ / /_/ / /_/ / / / # 53 | # /_/ /_/ \____/_/ \__,_/_/ \__/___/_____/_/ |_\____/ /_/ |_\__,_/\__/_/ /_/ # 54 | # # 55 | ######################################################################################## 56 | 57 | ################### 58 | # 注意事项 # 59 | ################### 60 | 61 | # 创建 OAuth2 应用 https://auth.tpcraft.net/oauth2/client 62 | # 如果域名未备案请使用IP作为回调地址 63 | 64 | ################### 65 | # 配置文件 # 66 | ################### 67 | 68 | # Web服务器端口 69 | webPort: 5900 70 | 71 | # OAuth2 72 | oauth2: 73 | clientId: '' # 标识 74 | clientSecret: '' # 密钥 75 | redirectUri: '' # 回调地址 76 | 77 | # 登入消息 78 | # 变量 %player%(玩家名称) 79 | loginMessage: 80 | enable: true # 是否启用 81 | join: '[&2+&r] &e%player%' # 进入消息 82 | leave: '[&4-&r] &e%player%' # 离开消息 83 | 84 | # 自动登入 85 | autoLogin: 86 | enable: false # 是否启用 87 | expires: 3600 # 超时时长(秒) 88 | 89 | # 固定登入坐标 90 | loginPosition: 91 | enable: false # 是否启用 92 | x: 0.0 # X轴 93 | y: 0.0 # Y轴 94 | z: 0.0 # Z轴 95 | 96 | # 白名单 97 | # 吐槽 原版白名单一点都不好用! 98 | whiteList: 99 | enable: false # 是否启用 100 | allowPlayers: [ ] # 白名单列表 101 | ``` 102 | -------------------------------------------------------------------------------- /TPCraftIDACAuth.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SPIGOT 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | net.tpcraft.minecraft 8 | TPCraftIDACAuth 9 | 1.2 10 | jar 11 | 12 | TPCraftIDACAuth 13 | 14 | 15 | 1.8 16 | UTF-8 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-compiler-plugin 24 | 3.8.1 25 | 26 | ${java.version} 27 | ${java.version} 28 | 29 | 30 | 31 | org.apache.maven.plugins 32 | maven-shade-plugin 33 | 3.2.4 34 | 35 | 36 | package 37 | 38 | shade 39 | 40 | 41 | false 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | src/main/resources 50 | true 51 | 52 | 53 | 54 | 55 | 56 | 57 | spigotmc-repo 58 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 59 | 60 | 61 | sonatype 62 | https://oss.sonatype.org/content/groups/public/ 63 | 64 | 65 | 66 | 67 | 68 | org.spigotmc 69 | spigot-api 70 | 1.12-R0.1-SNAPSHOT 71 | provided 72 | 73 | 74 | com.sparkjava 75 | spark-core 76 | 2.9.3 77 | 78 | 79 | com.squareup.okhttp3 80 | okhttp 81 | 4.9.1 82 | 83 | 84 | com.google.code.gson 85 | gson 86 | 2.8.9 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/Config.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft; 2 | 3 | import java.util.List; 4 | 5 | public class Config { 6 | private Integer webPort; 7 | private String oauth2ClientId; 8 | private String oauth2ClientSecret; 9 | private String oauth2RedirectUri; 10 | private Boolean loginMessageEnable; 11 | private String loginMessageJoin; 12 | private String loginMessageLeave; 13 | private Boolean autoLoginEnable; 14 | private Integer autoLoginExpires; 15 | private Boolean loginPositionEnable; 16 | private Double loginPositionX; 17 | private Double loginPositionY; 18 | private Double loginPositionZ; 19 | private Boolean whiteListEnable; 20 | private List whiteListAllowPlayers; 21 | 22 | public Config() { 23 | } 24 | 25 | public Integer getWebPort() { 26 | return webPort; 27 | } 28 | 29 | public void setWebPort(Integer webPort) { 30 | this.webPort = webPort; 31 | } 32 | 33 | public String getOauth2ClientId() { 34 | return oauth2ClientId; 35 | } 36 | 37 | public void setOauth2ClientId(String oauth2ClientId) { 38 | this.oauth2ClientId = oauth2ClientId; 39 | } 40 | 41 | public String getOauth2ClientSecret() { 42 | return oauth2ClientSecret; 43 | } 44 | 45 | public void setOauth2ClientSecret(String oauth2ClientSecret) { 46 | this.oauth2ClientSecret = oauth2ClientSecret; 47 | } 48 | 49 | public String getOauth2RedirectUri() { 50 | return oauth2RedirectUri; 51 | } 52 | 53 | public void setOauth2RedirectUri(String oauth2RedirectUri) { 54 | this.oauth2RedirectUri = oauth2RedirectUri; 55 | } 56 | 57 | public Boolean getLoginMessageEnable() { 58 | return loginMessageEnable; 59 | } 60 | 61 | public void setLoginMessageEnable(Boolean loginMessageEnable) { 62 | this.loginMessageEnable = loginMessageEnable; 63 | } 64 | 65 | public String getLoginMessageJoin() { 66 | return loginMessageJoin; 67 | } 68 | 69 | public void setLoginMessageJoin(String loginMessageJoin) { 70 | this.loginMessageJoin = loginMessageJoin; 71 | } 72 | 73 | public String getLoginMessageLeave() { 74 | return loginMessageLeave; 75 | } 76 | 77 | public void setLoginMessageLeave(String loginMessageLeave) { 78 | this.loginMessageLeave = loginMessageLeave; 79 | } 80 | 81 | public Boolean getAutoLoginEnable() { 82 | return autoLoginEnable; 83 | } 84 | 85 | public void setAutoLoginEnable(Boolean autoLoginEnable) { 86 | this.autoLoginEnable = autoLoginEnable; 87 | } 88 | 89 | public Integer getAutoLoginExpires() { 90 | return autoLoginExpires; 91 | } 92 | 93 | public void setAutoLoginExpires(Integer autoLoginExpires) { 94 | this.autoLoginExpires = autoLoginExpires; 95 | } 96 | 97 | public Boolean getLoginPositionEnable() { 98 | return loginPositionEnable; 99 | } 100 | 101 | public void setLoginPositionEnable(Boolean loginPositionEnable) { 102 | this.loginPositionEnable = loginPositionEnable; 103 | } 104 | 105 | public Double getLoginPositionX() { 106 | return loginPositionX; 107 | } 108 | 109 | public void setLoginPositionX(Double loginPositionX) { 110 | this.loginPositionX = loginPositionX; 111 | } 112 | 113 | public Double getLoginPositionY() { 114 | return loginPositionY; 115 | } 116 | 117 | public void setLoginPositionY(Double loginPositionY) { 118 | this.loginPositionY = loginPositionY; 119 | } 120 | 121 | public Double getLoginPositionZ() { 122 | return loginPositionZ; 123 | } 124 | 125 | public void setLoginPositionZ(Double loginPositionZ) { 126 | this.loginPositionZ = loginPositionZ; 127 | } 128 | 129 | public Boolean getWhiteListEnable() { 130 | return whiteListEnable; 131 | } 132 | 133 | public void setWhiteListEnable(Boolean whiteListEnable) { 134 | this.whiteListEnable = whiteListEnable; 135 | } 136 | 137 | public List getWhiteListAllowPlayers() { 138 | return whiteListAllowPlayers; 139 | } 140 | 141 | public void setWhiteListAllowPlayers(List whiteListAllowPlayers) { 142 | this.whiteListAllowPlayers = whiteListAllowPlayers; 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/TPCraftIDACAuth.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft; 2 | 3 | import net.tpcraft.minecraft.command.MainCommand; 4 | import net.tpcraft.minecraft.command.MainTabCompleter; 5 | import net.tpcraft.minecraft.event.JoinEvent; 6 | import net.tpcraft.minecraft.event.LeaveEvent; 7 | import net.tpcraft.minecraft.event.MainEvent; 8 | import net.tpcraft.minecraft.server.http.WebServer; 9 | import org.bukkit.configuration.Configuration; 10 | import org.bukkit.configuration.file.FileConfiguration; 11 | import org.bukkit.configuration.file.YamlConfiguration; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.plugin.Plugin; 14 | import org.bukkit.plugin.java.JavaPlugin; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.nio.charset.StandardCharsets; 19 | import java.nio.file.Files; 20 | import java.nio.file.Paths; 21 | import java.util.ArrayList; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | public final class TPCraftIDACAuth extends JavaPlugin { 27 | public static final String prefix = "&c&l[TPCraftIDAC Auth] &r&8>>&r "; 28 | 29 | public static Boolean loaded = false; 30 | 31 | public static Plugin plugin; 32 | 33 | public static Config config = new Config(); 34 | 35 | public static String templateFilePath = "/template/index.html"; 36 | public static String templateContent = ""; 37 | 38 | public static String autoLoginDataFilePath = "/data/autoLoginData.yml"; 39 | public static List> autoLoginData = new ArrayList<>(); 40 | 41 | public static Map notLoginPlayers = new HashMap<>(); 42 | public static Map isLoginPlayers = new HashMap<>(); 43 | 44 | @Override 45 | public void onEnable() { 46 | getLogger().info(" __________ ______ ______ ________ ___ ______ ___ __ __ "); 47 | getLogger().info(" /_ __/ __ \\/ ____/________ _/ __/ /_/ _/ __ \\/ | / ____/ / | __ __/ /_/ /_ "); 48 | getLogger().info(" / / / /_/ / / / ___/ __ `/ /_/ __// // / / / /| |/ / / /| |/ / / / __/ __ \\"); 49 | getLogger().info(" / / / ____/ /___/ / / /_/ / __/ /__/ // /_/ / ___ / /___ / ___ / /_/ / /_/ / / /"); 50 | getLogger().info("/_/ /_/ \\____/_/ \\__,_/_/ \\__/___/_____/_/ |_\\____/ /_/ |_\\__,_/\\__/_/ /_/ "); 51 | 52 | plugin = getPlugin(getClass()); 53 | 54 | saveDefaultConfig(); 55 | saveResource("data/autoLoginData.yml", false); 56 | saveResource("template/index.html", false); 57 | 58 | getLogger().info("加载配置文件、数据与模板..."); 59 | loadConfig(); 60 | loadData(); 61 | loadTemplate(); 62 | 63 | getLogger().info("注册命令..."); 64 | getCommand("auth").setExecutor(new MainCommand()); 65 | getCommand("auth").setTabCompleter(new MainTabCompleter()); 66 | 67 | getLogger().info("监听事件..."); 68 | getServer().getPluginManager().registerEvents(new JoinEvent(), this); 69 | getServer().getPluginManager().registerEvents(new LeaveEvent(), this); 70 | getServer().getPluginManager().registerEvents(new MainEvent(), this); 71 | 72 | getLogger().info("在 " + config.getWebPort() + " 端口启动Web服务器..."); 73 | WebServer.start(); 74 | 75 | getLogger().info("插件已加载!"); 76 | loaded = true; 77 | } 78 | 79 | @Override 80 | public void onDisable() { 81 | getLogger().info("插件已卸载!"); 82 | } 83 | 84 | public static void loadConfig() { 85 | Configuration configuration = plugin.getConfig(); 86 | 87 | config.setWebPort(configuration.getInt("webPort", 5900)); 88 | 89 | config.setOauth2ClientId(configuration.getString("oauth2.clientId", "")); 90 | config.setOauth2ClientSecret(configuration.getString("oauth2.clientSecret", "")); 91 | config.setOauth2RedirectUri(configuration.getString("oauth2.redirectUri", "")); 92 | 93 | config.setLoginMessageEnable(configuration.getBoolean("loginMessage.enable", true)); 94 | config.setLoginMessageJoin(configuration.getString("loginMessage.join", "[&2+&r] &e%player%")); 95 | config.setLoginMessageLeave(configuration.getString("loginMessage.leave", "[&4-&r] &e%player%")); 96 | 97 | config.setAutoLoginEnable(configuration.getBoolean("autoLogin.enable", true)); 98 | config.setAutoLoginExpires(configuration.getInt("autoLogin.expires", 3600)); 99 | 100 | config.setLoginPositionEnable(configuration.getBoolean("loginPosition.enable", false)); 101 | config.setLoginPositionX(configuration.getDouble("loginPosition.x", 0.0)); 102 | config.setLoginPositionY(configuration.getDouble("loginPosition.y", 0.0)); 103 | config.setLoginPositionZ(configuration.getDouble("loginPosition.z", 0.0)); 104 | 105 | config.setWhiteListEnable(configuration.getBoolean("whiteList.enable", false)); 106 | config.setWhiteListAllowPlayers(configuration.getStringList("whiteList.allowPlayers")); 107 | } 108 | 109 | public static void loadData() { 110 | FileConfiguration configuration = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder() + autoLoginDataFilePath)); 111 | 112 | autoLoginData = configuration.getMapList("players"); 113 | } 114 | 115 | public static void saveData() { 116 | FileConfiguration configuration = YamlConfiguration.loadConfiguration(new File(plugin.getDataFolder() + autoLoginDataFilePath)); 117 | 118 | configuration.set("players", autoLoginData); 119 | 120 | try { 121 | configuration.save(new File(plugin.getDataFolder() + autoLoginDataFilePath)); 122 | } catch (IOException e) { 123 | e.printStackTrace(); 124 | } 125 | } 126 | 127 | public static void loadTemplate() { 128 | templateContent = ""; 129 | 130 | String templatePath = plugin.getDataFolder() + templateFilePath; 131 | 132 | if (new File(templatePath).exists()) { 133 | try { 134 | List lines = Files.readAllLines(Paths.get(templatePath), StandardCharsets.UTF_8); 135 | for (String line : lines) { 136 | templateContent += line; 137 | } 138 | } catch (IOException e) { 139 | e.printStackTrace(); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/command/MainCommand.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.command; 2 | 3 | import net.tpcraft.minecraft.Config; 4 | import net.tpcraft.minecraft.TPCraftIDACAuth; 5 | import net.tpcraft.minecraft.server.http.WebServer; 6 | import org.bukkit.ChatColor; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.plugin.Plugin; 12 | import org.bukkit.scheduler.BukkitRunnable; 13 | 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.regex.Pattern; 17 | 18 | public class MainCommand implements CommandExecutor { 19 | private Boolean checkArgs(CommandSender sender, String[] args, Integer argsLength) { 20 | if (args.length < argsLength || args[argsLength - 1].isEmpty()) { 21 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 22 | TPCraftIDACAuth.prefix + "参数错误" 23 | )); 24 | return false; 25 | } 26 | return true; 27 | } 28 | 29 | private Boolean checkSenderIsConsole(CommandSender sender) { 30 | return !(sender instanceof Player); 31 | } 32 | 33 | private Boolean checkSenderIsPlayer(CommandSender sender) { 34 | return sender instanceof Player; 35 | } 36 | 37 | private void sendHelp(CommandSender sender) { 38 | Config config = TPCraftIDACAuth.config; 39 | 40 | sender.sendMessage(""); 41 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 42 | TPCraftIDACAuth.prefix + "帮助" 43 | )); 44 | sender.sendMessage(""); 45 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 46 | "登入消息:" + (config.getLoginMessageEnable() ? "&a已启用" : "&c已禁用") 47 | )); 48 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 49 | "自动登入:" + (config.getAutoLoginEnable() ? "&a已启用" : "&c已禁用") 50 | )); 51 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 52 | "固定登入坐标:" + (config.getLoginPositionEnable() ? "&a已启用" : "&c已禁用") 53 | )); 54 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 55 | "白名单:" + (config.getWhiteListEnable() ? "&a已启用" : "&c已禁用") 56 | )); 57 | sender.sendMessage(""); 58 | sender.sendMessage("/auth - 主命令"); 59 | sender.sendMessage("* /auth loginMessage on - 启用登入消息"); 60 | sender.sendMessage("* /auth loginMessage off - 禁用登入消息"); 61 | sender.sendMessage("* /auth autoLogin on - 启用自动登入"); 62 | sender.sendMessage("* /auth autoLogin off - 禁用自动登入"); 63 | sender.sendMessage("* /auth autoLogin set <超时时间(秒)> - 设置自动登入超时时间"); 64 | sender.sendMessage("* /auth loginPosition on - 启用固定登入坐标"); 65 | sender.sendMessage("* /auth loginPosition off - 禁用固定登入坐标"); 66 | sender.sendMessage("* /auth loginPosition set - 设置固定登入坐标"); 67 | sender.sendMessage("* /auth whiteList on - 启用白名单"); 68 | sender.sendMessage("* /auth whiteList off - 禁用白名单"); 69 | sender.sendMessage("* /auth whiteList add <玩家名称> - 添加白名单"); 70 | sender.sendMessage("* /auth whiteList remove <玩家名称> - 移除白名单"); 71 | sender.sendMessage("* /auth whiteList list - 白名单列表"); 72 | sender.sendMessage("* /auth reload - 重载插件"); 73 | sender.sendMessage(""); 74 | sender.sendMessage("注意:带 * 字符需要管理员权限"); 75 | sender.sendMessage(""); 76 | } 77 | 78 | @Override 79 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 80 | if (args.length == 0) { 81 | sendHelp(sender); 82 | return false; 83 | } else { 84 | if (sender instanceof Player && !sender.hasPermission("auth.admin")) { 85 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 86 | TPCraftIDACAuth.prefix + "你没有执行此命令的权限" 87 | )); 88 | return false; 89 | } 90 | } 91 | 92 | Plugin plugin = TPCraftIDACAuth.plugin; 93 | Config config = TPCraftIDACAuth.config; 94 | 95 | switch (args[0]) { 96 | case "loginMessage": { 97 | if (!checkArgs(sender, args, 2)) { 98 | return false; 99 | } 100 | 101 | switch (args[1]) { 102 | case "on": { 103 | config.setLoginMessageEnable(true); 104 | plugin.getConfig().set("loginMessage.enable", true); 105 | plugin.saveConfig(); 106 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 107 | TPCraftIDACAuth.prefix + "登入消息:&2已启用" 108 | )); 109 | return false; 110 | } 111 | case "off": { 112 | config.setLoginMessageEnable(false); 113 | plugin.getConfig().set("loginMessage.enable", false); 114 | plugin.saveConfig(); 115 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 116 | TPCraftIDACAuth.prefix + "登入消息:&4已禁用" 117 | )); 118 | return false; 119 | } 120 | } 121 | } 122 | case "autoLogin": { 123 | if (!checkArgs(sender, args, 2)) { 124 | return false; 125 | } 126 | 127 | switch (args[1]) { 128 | case "on": { 129 | config.setAutoLoginEnable(true); 130 | plugin.getConfig().set("autoLogin.enable", true); 131 | plugin.saveConfig(); 132 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 133 | TPCraftIDACAuth.prefix + "自动登入:&2已启用" 134 | )); 135 | return false; 136 | } 137 | case "off": { 138 | config.setAutoLoginEnable(false); 139 | plugin.getConfig().set("autoLogin.enable", false); 140 | plugin.saveConfig(); 141 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 142 | TPCraftIDACAuth.prefix + "自动登入:&4已禁用" 143 | )); 144 | return false; 145 | } 146 | case "set": { 147 | if (!checkArgs(sender, args, 3)) { 148 | return false; 149 | } 150 | 151 | if (!Pattern.matches("^[0-9]+$", args[2])) { 152 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 153 | TPCraftIDACAuth.prefix + "参数错误" 154 | )); 155 | return false; 156 | } 157 | 158 | config.setAutoLoginExpires(Integer.parseInt(args[2])); 159 | plugin.getConfig().set("autoLogin.expires", Integer.parseInt(args[2])); 160 | plugin.saveConfig(); 161 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 162 | TPCraftIDACAuth.prefix + "自动登入:超时时间设置为 " + args[2] + " 秒" 163 | )); 164 | return false; 165 | } 166 | } 167 | } 168 | case "loginPosition": { 169 | if (!checkArgs(sender, args, 2)) { 170 | return false; 171 | } 172 | 173 | switch (args[1]) { 174 | case "on": { 175 | config.setLoginPositionEnable(true); 176 | plugin.getConfig().set("loginPosition.enable", true); 177 | plugin.saveConfig(); 178 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 179 | TPCraftIDACAuth.prefix + "固定登入坐标:&2已启用" 180 | )); 181 | return false; 182 | } 183 | case "off": { 184 | config.setLoginPositionEnable(false); 185 | plugin.getConfig().set("loginPosition.enable", false); 186 | plugin.saveConfig(); 187 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 188 | TPCraftIDACAuth.prefix + "固定登入坐标:&4已禁用" 189 | )); 190 | return false; 191 | } 192 | case "set": { 193 | if (!checkSenderIsPlayer(sender)) { 194 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 195 | TPCraftIDACAuth.prefix + "此命令控制台无法使用" 196 | )); 197 | return false; 198 | } 199 | 200 | Player player = (Player) sender; 201 | 202 | double x = player.getLocation().getX(); 203 | double y = player.getLocation().getY(); 204 | double z = player.getLocation().getZ(); 205 | 206 | x = Math.round(x * 10.0) / 10.0; 207 | y = Math.round(y * 10.0) / 10.0; 208 | z = Math.round(z * 10.0) / 10.0; 209 | 210 | config.setLoginPositionX(x); 211 | config.setLoginPositionY(y); 212 | config.setLoginPositionZ(z); 213 | plugin.getConfig().set("loginPosition.x", x); 214 | plugin.getConfig().set("loginPosition.y", y); 215 | plugin.getConfig().set("loginPosition.z", z); 216 | plugin.saveConfig(); 217 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 218 | TPCraftIDACAuth.prefix + "固定登入坐标:已设置为 X:" + x + " Y:" + y + " Z:" + z 219 | )); 220 | return false; 221 | } 222 | } 223 | } 224 | case "whiteList": { 225 | if (!checkArgs(sender, args, 2)) { 226 | return false; 227 | } 228 | 229 | switch (args[1]) { 230 | case "on": { 231 | config.setWhiteListEnable(true); 232 | plugin.getConfig().set("whiteList.enable", true); 233 | plugin.saveConfig(); 234 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 235 | TPCraftIDACAuth.prefix + "白名单:&2已启用" 236 | )); 237 | return false; 238 | } 239 | case "off": { 240 | config.setWhiteListEnable(false); 241 | plugin.getConfig().set("whiteList.enable", false); 242 | plugin.saveConfig(); 243 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 244 | TPCraftIDACAuth.prefix + "白名单:&4已禁用" 245 | )); 246 | return false; 247 | } 248 | case "add": { 249 | if (!checkArgs(sender, args, 3)) { 250 | return false; 251 | } 252 | config.getWhiteListAllowPlayers().add(args[2]); 253 | plugin.getConfig().set("whiteList.allowPlayers", config.getWhiteListAllowPlayers()); 254 | plugin.saveConfig(); 255 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 256 | TPCraftIDACAuth.prefix + "白名单:已添加 &e" + args[2] 257 | )); 258 | return false; 259 | } 260 | case "remove": { 261 | if (!checkArgs(sender, args, 3)) { 262 | return false; 263 | } 264 | config.getWhiteListAllowPlayers().removeIf(player -> player.equals(args[2])); 265 | plugin.getConfig().set("whiteList.allowPlayers", config.getWhiteListAllowPlayers()); 266 | plugin.saveConfig(); 267 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 268 | TPCraftIDACAuth.prefix + "白名单:已移除 &e" + args[2] 269 | )); 270 | return false; 271 | } 272 | case "list": { 273 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 274 | TPCraftIDACAuth.prefix + "白名单列表:&e" + String.join(" ", config.getWhiteListAllowPlayers()) 275 | )); 276 | return false; 277 | } 278 | } 279 | } 280 | case "reload": { 281 | for (Map.Entry entry : TPCraftIDACAuth.notLoginPlayers.entrySet()) { 282 | Player player = (Player) entry.getValue(); 283 | new BukkitRunnable() { 284 | @Override 285 | public void run() { 286 | player.kickPlayer(ChatColor.translateAlternateColorCodes('&', 287 | TPCraftIDACAuth.prefix + "插件重载,请稍后再重试" 288 | )); 289 | } 290 | }.runTask(plugin); 291 | } 292 | TPCraftIDACAuth.notLoginPlayers = new HashMap<>(); 293 | 294 | TPCraftIDACAuth.loaded = false; 295 | 296 | plugin.reloadConfig(); 297 | 298 | TPCraftIDACAuth.loadConfig(); 299 | TPCraftIDACAuth.loadData(); 300 | TPCraftIDACAuth.loadTemplate(); 301 | 302 | WebServer.stop(); 303 | new BukkitRunnable() { 304 | @Override 305 | public void run() { 306 | WebServer.start(); 307 | 308 | sender.sendMessage(ChatColor.translateAlternateColorCodes('&', 309 | TPCraftIDACAuth.prefix + "插件重载完成" 310 | )); 311 | 312 | TPCraftIDACAuth.loaded = true; 313 | } 314 | }.runTaskLater(plugin, 60); 315 | return false; 316 | } 317 | default: { 318 | sendHelp(sender); 319 | return false; 320 | } 321 | } 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/command/MainTabCompleter.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.command; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.command.TabCompleter; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class MainTabCompleter implements TabCompleter { 11 | @Override 12 | public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { 13 | List completions = new ArrayList<>(); 14 | 15 | if (args.length == 1) { 16 | completions.add("loginMessage"); 17 | completions.add("autoLogin"); 18 | completions.add("loginPosition"); 19 | completions.add("whiteList"); 20 | completions.add("reload"); 21 | } 22 | 23 | switch (args[0]) { 24 | case "loginMessage": { 25 | completions.add("on"); 26 | completions.add("off"); 27 | break; 28 | } 29 | case "autoLogin": 30 | case "loginPosition": { 31 | completions.add("on"); 32 | completions.add("off"); 33 | completions.add("set"); 34 | break; 35 | } 36 | case "whiteList": { 37 | completions.add("on"); 38 | completions.add("off"); 39 | completions.add("add"); 40 | completions.add("remove"); 41 | completions.add("list"); 42 | break; 43 | } 44 | } 45 | 46 | return completions; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/event/JoinEvent.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.event; 2 | 3 | import com.google.gson.Gson; 4 | import net.md_5.bungee.api.chat.ClickEvent; 5 | import net.md_5.bungee.api.chat.ComponentBuilder; 6 | import net.tpcraft.minecraft.Config; 7 | import net.tpcraft.minecraft.TPCraftIDACAuth; 8 | import net.tpcraft.minecraft.util.HTTPRequest; 9 | import net.tpcraft.minecraft.util.MapList; 10 | import org.bukkit.ChatColor; 11 | import org.bukkit.Location; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.event.EventHandler; 14 | import org.bukkit.event.EventPriority; 15 | import org.bukkit.event.Listener; 16 | import org.bukkit.event.player.PlayerJoinEvent; 17 | import org.bukkit.event.player.PlayerLoginEvent; 18 | import org.bukkit.scheduler.BukkitRunnable; 19 | 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.UUID; 24 | 25 | import static net.tpcraft.minecraft.util.Moment.timestampToDate; 26 | 27 | public class JoinEvent implements Listener { 28 | private Boolean checkAutoLogin(Player player, String state) { 29 | Config config = TPCraftIDACAuth.config; 30 | List> autoLoginData = TPCraftIDACAuth.autoLoginData; 31 | 32 | Map playerData = MapList.search(autoLoginData, "name", player.getDisplayName()); 33 | if (playerData == null) { 34 | return false; 35 | } 36 | 37 | String ip = String.valueOf(playerData.get("ip")); 38 | Long lastLoginAt = Long.parseLong(String.valueOf(playerData.get("lastLoginAt"))); 39 | 40 | if (!ip.equals(player.getAddress().getAddress().getHostAddress())) { 41 | player.sendMessage(""); 42 | player.sendMessage(ChatColor.translateAlternateColorCodes('&', 43 | TPCraftIDACAuth.prefix + "IP地址已变更,请重新授权登入" 44 | )); 45 | player.sendMessage(""); 46 | return false; 47 | } 48 | 49 | if (lastLoginAt + (config.getAutoLoginExpires() * 1000) < System.currentTimeMillis()) { 50 | player.sendMessage(""); 51 | player.sendMessage(ChatColor.translateAlternateColorCodes('&', 52 | TPCraftIDACAuth.prefix + "自动登入已超时,请重新授权登入" 53 | )); 54 | player.sendMessage(""); 55 | return false; 56 | } 57 | 58 | TPCraftIDACAuth.isLoginPlayers.put(player, state); 59 | 60 | player.sendMessage(""); 61 | player.sendMessage(ChatColor.translateAlternateColorCodes('&', 62 | TPCraftIDACAuth.prefix + "已自动登入,上次登入的时间为:" + timestampToDate(lastLoginAt) 63 | )); 64 | player.sendMessage(""); 65 | 66 | return true; 67 | } 68 | 69 | @EventHandler(priority = EventPriority.HIGH) 70 | public void PlayerLoginEvent(PlayerLoginEvent event) { 71 | Config config = TPCraftIDACAuth.config; 72 | 73 | Player player = event.getPlayer(); 74 | 75 | if (!TPCraftIDACAuth.loaded) { 76 | event.disallow(PlayerLoginEvent.Result.KICK_OTHER, ChatColor.translateAlternateColorCodes('&', 77 | TPCraftIDACAuth.prefix + "插件未加载完成,请稍后重试" 78 | )); 79 | return; 80 | } 81 | 82 | if (config.getWhiteListEnable() && !config.getWhiteListAllowPlayers().contains(player.getDisplayName())) { 83 | event.disallow(PlayerLoginEvent.Result.KICK_OTHER, ChatColor.translateAlternateColorCodes('&', 84 | TPCraftIDACAuth.prefix + "已启用白名单,您不存在白名单内" 85 | )); 86 | return; 87 | } 88 | 89 | String responseGetUser = HTTPRequest.sendGetRequest( 90 | "https://api.tpcraft.net/user/username/" + player.getDisplayName(), 91 | new HashMap<>(), 92 | new HashMap<>() 93 | ); 94 | 95 | if (responseGetUser.equals("ERROR")) { 96 | event.disallow(PlayerLoginEvent.Result.KICK_OTHER, ChatColor.translateAlternateColorCodes('&', 97 | TPCraftIDACAuth.prefix + "授权错误\n\n错误类型:内部错误\n错误原因:获取用户信息时发生错误\n若出现此错误,您可以将此错误反馈给服务器管理员" 98 | )); 99 | } else { 100 | Map response = new Gson().fromJson(responseGetUser, Map.class); 101 | if (response.get("status").toString().equals("false")) { 102 | event.disallow(PlayerLoginEvent.Result.KICK_OTHER, ChatColor.translateAlternateColorCodes('&', 103 | TPCraftIDACAuth.prefix + "此用户名未注册,请到 https://auth.tpcraft.net 注册" 104 | )); 105 | } 106 | } 107 | } 108 | 109 | @EventHandler(priority = EventPriority.HIGH) 110 | public void PlayerJoinEvent(PlayerJoinEvent event) { 111 | Config config = TPCraftIDACAuth.config; 112 | 113 | Player player = event.getPlayer(); 114 | String state = UUID.randomUUID().toString().replaceAll("-", ""); 115 | 116 | if (config.getLoginMessageEnable()) { 117 | event.setJoinMessage(ChatColor.translateAlternateColorCodes('&', 118 | config.getLoginMessageJoin().replace("%player%", player.getDisplayName()) 119 | )); 120 | } 121 | 122 | if (config.getLoginPositionEnable()) { 123 | new BukkitRunnable() { 124 | @Override 125 | public void run() { 126 | player.teleport(new Location( 127 | player.getWorld(), 128 | config.getLoginPositionX(), 129 | config.getLoginPositionY(), 130 | config.getLoginPositionZ()) 131 | ); 132 | } 133 | }.runTask(TPCraftIDACAuth.plugin); 134 | } 135 | 136 | if (config.getAutoLoginEnable() && checkAutoLogin(player, state)) { 137 | return; 138 | } 139 | 140 | TPCraftIDACAuth.notLoginPlayers.put(state, player); 141 | 142 | ComponentBuilder componentBuilder = new ComponentBuilder("打开聊天框点击此处授权(120秒超时)") 143 | .bold(true) 144 | .underlined(true) 145 | .event(new ClickEvent( 146 | ClickEvent.Action.OPEN_URL, 147 | "https://auth.tpcraft.net/oauth2/authorize?" + 148 | "client_id=" + config.getOauth2ClientId() + 149 | "&redirect_uri=" + config.getOauth2RedirectUri() + 150 | "&response_type=code" + 151 | "&state=" + state 152 | )); 153 | 154 | player.sendMessage(""); 155 | player.sendMessage(ChatColor.translateAlternateColorCodes('&', 156 | TPCraftIDACAuth.prefix + "授权登入" 157 | )); 158 | player.sendMessage(""); 159 | player.spigot().sendMessage(componentBuilder.create()); 160 | player.sendMessage(""); 161 | 162 | final int[] second = {120}; 163 | new BukkitRunnable() { 164 | @Override 165 | public void run() { 166 | if (TPCraftIDACAuth.notLoginPlayers.get(state) == null) { 167 | this.cancel(); 168 | return; 169 | } 170 | second[0]--; 171 | if (second[0] == 0) { 172 | player.kickPlayer(ChatColor.translateAlternateColorCodes('&', 173 | TPCraftIDACAuth.prefix + "授权已超时" 174 | )); 175 | } 176 | } 177 | }.runTaskTimer(TPCraftIDACAuth.plugin, 0, 20); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/event/LeaveEvent.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.event; 2 | 3 | import net.tpcraft.minecraft.Config; 4 | import net.tpcraft.minecraft.TPCraftIDACAuth; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.EventPriority; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.player.PlayerQuitEvent; 11 | 12 | public class LeaveEvent implements Listener { 13 | @EventHandler(priority = EventPriority.HIGH) 14 | public void PlayerQuitEvent(PlayerQuitEvent event) { 15 | Config config = TPCraftIDACAuth.config; 16 | 17 | Player player = event.getPlayer(); 18 | 19 | if (TPCraftIDACAuth.notLoginPlayers.containsValue(player)) { 20 | TPCraftIDACAuth.notLoginPlayers.entrySet().removeIf(entry -> player == entry.getValue()); 21 | } 22 | 23 | if (TPCraftIDACAuth.isLoginPlayers.get(player) != null) { 24 | TPCraftIDACAuth.isLoginPlayers.remove(player); 25 | } 26 | 27 | if (config.getLoginMessageEnable()) { 28 | event.setQuitMessage(ChatColor.translateAlternateColorCodes('&', 29 | config.getLoginMessageLeave().replace("%player%", player.getDisplayName()) 30 | )); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/event/MainEvent.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.event; 2 | 3 | import net.tpcraft.minecraft.TPCraftIDACAuth; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.EventHandler; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.entity.EntityDamageEvent; 8 | import org.bukkit.event.inventory.InventoryClickEvent; 9 | import org.bukkit.event.player.*; 10 | 11 | public class MainEvent implements Listener { 12 | private boolean checkIsLogin(Player player) { 13 | return TPCraftIDACAuth.isLoginPlayers.get(player) == null; 14 | } 15 | 16 | @EventHandler 17 | public void InventoryClickEvent(InventoryClickEvent event) { 18 | if (event.getWhoClicked() instanceof Player) { 19 | event.setCancelled(checkIsLogin(((Player) event.getWhoClicked()).getPlayer())); 20 | } 21 | } 22 | 23 | @EventHandler 24 | public void PlayerPortalEvent(PlayerPortalEvent event) { 25 | event.setCancelled(checkIsLogin(event.getPlayer())); 26 | } 27 | 28 | @EventHandler 29 | public void PlayerCommandPreprocessEvent(PlayerCommandPreprocessEvent event) { 30 | event.setCancelled(checkIsLogin(event.getPlayer())); 31 | } 32 | 33 | @EventHandler 34 | public void PlayerPickupItemEvent(PlayerPickupItemEvent event) { 35 | event.setCancelled(checkIsLogin(event.getPlayer())); 36 | } 37 | 38 | @EventHandler 39 | public void PlayerDropItemEvent(PlayerDropItemEvent event) { 40 | event.setCancelled(checkIsLogin(event.getPlayer())); 41 | } 42 | 43 | @EventHandler 44 | public void PlayerInteractEvent(PlayerInteractEvent event) { 45 | event.setCancelled(checkIsLogin(event.getPlayer())); 46 | } 47 | 48 | @EventHandler 49 | public void PlayerItemHeldEvent(PlayerItemHeldEvent event) { 50 | event.setCancelled(checkIsLogin(event.getPlayer())); 51 | } 52 | 53 | @EventHandler 54 | public void PlayerMoveEvent(PlayerMoveEvent event) { 55 | event.setCancelled(checkIsLogin(event.getPlayer())); 56 | } 57 | 58 | @EventHandler 59 | public void AsyncPlayerChatEvent(AsyncPlayerChatEvent event) { 60 | event.setCancelled(checkIsLogin(event.getPlayer())); 61 | } 62 | 63 | @EventHandler 64 | public void EntityDamageEvent(EntityDamageEvent event) { 65 | if (event.getEntity() instanceof Player) { 66 | event.setCancelled(checkIsLogin(((Player) event.getEntity()).getPlayer())); 67 | } 68 | } 69 | 70 | @EventHandler 71 | public void PlayerTeleportEvent(PlayerTeleportEvent event) { 72 | PlayerTeleportEvent.TeleportCause teleportCause = event.getCause(); 73 | 74 | if (teleportCause == PlayerTeleportEvent.TeleportCause.PLUGIN || teleportCause == PlayerTeleportEvent.TeleportCause.COMMAND) { 75 | return; 76 | } 77 | 78 | event.setCancelled(checkIsLogin(event.getPlayer())); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/server/http/WebServer.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.server.http; 2 | 3 | import net.tpcraft.minecraft.TPCraftIDACAuth; 4 | import net.tpcraft.minecraft.server.http.controller.Oauth2Controller; 5 | import spark.Spark; 6 | 7 | public class WebServer { 8 | public static void start() { 9 | Spark.port(TPCraftIDACAuth.config.getWebPort()); 10 | 11 | new Oauth2Controller(); 12 | 13 | Spark.get("/", (req, res) -> "TPCraftIDAC Auth Plugin WebServer, TPCraftIDAC: https://auth.tpcraft.net/"); 14 | } 15 | 16 | public static void stop() { 17 | Spark.stop(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/server/http/controller/Oauth2Controller.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.server.http.controller; 2 | 3 | import com.google.gson.Gson; 4 | import net.tpcraft.minecraft.Config; 5 | import net.tpcraft.minecraft.TPCraftIDACAuth; 6 | import net.tpcraft.minecraft.util.HTTPRequest; 7 | import net.tpcraft.minecraft.util.MapList; 8 | import org.bukkit.ChatColor; 9 | import org.bukkit.Location; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.scheduler.BukkitRunnable; 12 | import spark.Spark; 13 | 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | public class Oauth2Controller { 19 | private String authorizationResults(String state, Boolean status, String title, Boolean errorDisplay, String error, String errorDescription) { 20 | Config config = TPCraftIDACAuth.config; 21 | String templateContent = TPCraftIDACAuth.templateContent; 22 | 23 | Player player = TPCraftIDACAuth.notLoginPlayers.get(state); 24 | 25 | templateContent = templateContent 26 | .replace("{{status}}", status ? "success" : "fail") 27 | .replace("{{title}}", title) 28 | .replace("{{errorDisplay}}", errorDisplay ? "block" : "none") 29 | .replace("{{error}}", error) 30 | .replace("{{errorDescription}}", errorDescription); 31 | 32 | if (status) { 33 | if (config.getAutoLoginEnable()) { 34 | TPCraftIDACAuth.autoLoginData = MapList.save( 35 | TPCraftIDACAuth.autoLoginData, 36 | new HashMap() { 37 | { 38 | put("name", player.getDisplayName()); 39 | put("ip", player.getAddress().getAddress().getHostAddress()); 40 | put("lastLoginAt", System.currentTimeMillis()); 41 | } 42 | }, 43 | "name", 44 | player.getDisplayName() 45 | ); 46 | TPCraftIDACAuth.saveData(); 47 | } 48 | 49 | TPCraftIDACAuth.notLoginPlayers.remove(state); 50 | TPCraftIDACAuth.isLoginPlayers.put(player, state); 51 | 52 | player.sendMessage(""); 53 | player.sendMessage(ChatColor.translateAlternateColorCodes('&', 54 | TPCraftIDACAuth.prefix + "授权成功" 55 | )); 56 | player.sendMessage(""); 57 | } else { 58 | if (player != null) { 59 | new BukkitRunnable() { 60 | @Override 61 | public void run() { 62 | player.kickPlayer(ChatColor.translateAlternateColorCodes('&', 63 | TPCraftIDACAuth.prefix + "授权失败" 64 | )); 65 | } 66 | }.runTask(TPCraftIDACAuth.plugin); 67 | 68 | TPCraftIDACAuth.notLoginPlayers.remove(state); 69 | } 70 | } 71 | 72 | return templateContent; 73 | } 74 | 75 | public Oauth2Controller() { 76 | Spark.get("/oauth2/callback", (req, res) -> { 77 | Config config = TPCraftIDACAuth.config; 78 | 79 | String reqDataError = req.queryParams("error"); 80 | String reqDataErrorDescription = req.queryParams("error_description"); 81 | String reqDataCode = req.queryParams("code"); 82 | String reqDataState = req.queryParams("state"); 83 | 84 | String accessToken; 85 | Map user; 86 | Player player = TPCraftIDACAuth.notLoginPlayers.get(reqDataState); 87 | 88 | if (player == null) { 89 | return authorizationResults( 90 | reqDataState, false, "授权失败", false, "", "" 91 | ); 92 | } 93 | 94 | if (reqDataError != null) { 95 | return authorizationResults( 96 | reqDataState, false, "授权错误", true, reqDataError, reqDataErrorDescription 97 | ); 98 | } 99 | 100 | String responseAccessToken = HTTPRequest.sendPostRequest( 101 | "https://api.tpcraft.net/oauth2/accessToken", 102 | new HashMap<>(), 103 | "client_id=" + config.getOauth2ClientId() + 104 | "&client_secret=" + config.getOauth2ClientSecret() + 105 | "&redirect_uri=" + config.getOauth2RedirectUri() + 106 | "&grant_type=authorization_code" + 107 | "&code=" + reqDataCode, 108 | new HashMap<>(), 109 | false 110 | ); 111 | 112 | if (responseAccessToken.equals("ERROR")) { 113 | return authorizationResults( 114 | reqDataState, false, "授权错误", true, "内部错误", "获取令牌时请求错误" 115 | ); 116 | } else { 117 | Map response = new Gson().fromJson(responseAccessToken, Map.class); 118 | if (response.get("access_token") != null) { 119 | accessToken = response.get("access_token").toString(); 120 | } else { 121 | return authorizationResults( 122 | reqDataState, false, "授权失败", false, "", "" 123 | ); 124 | } 125 | } 126 | 127 | String responseUser = HTTPRequest.sendGetRequest( 128 | "https://api.tpcraft.net/oauth2/user", 129 | new HashMap() { 130 | { 131 | put("Authorization", "Bearer " + accessToken); 132 | } 133 | }, 134 | new HashMap<>() 135 | ); 136 | 137 | if (responseUser.equals("ERROR")) { 138 | return authorizationResults( 139 | reqDataState, false, "授权错误", true, "内部错误", "获取用户信息时请求错误" 140 | ); 141 | } else { 142 | Map response = new Gson().fromJson(responseUser, Map.class); 143 | if (Boolean.parseBoolean(response.get("status").toString())) { 144 | user = (Map) response.get("data"); 145 | } else { 146 | return authorizationResults( 147 | reqDataState, false, "授权失败", false, "", "" 148 | ); 149 | } 150 | } 151 | 152 | if (!player.getDisplayName().equals(user.get("username").toString())) { 153 | return authorizationResults( 154 | reqDataState, false, "授权失败", false, "", "" 155 | ); 156 | } 157 | 158 | return authorizationResults(reqDataState, true, "授权成功", false, "", ""); 159 | }); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/util/HTTPRequest.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.util; 2 | 3 | import okhttp3.*; 4 | 5 | import java.util.Map; 6 | 7 | public class HTTPRequest { 8 | private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8"); 9 | private static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8"); 10 | 11 | private static final OkHttpClient client = new OkHttpClient(); 12 | 13 | public static String sendDeleteRequest(String url, Map headers, String data, Map params) { 14 | Request.Builder requestBuilder = new Request.Builder().url(buildUrlWithParams(url, params)).delete(); 15 | 16 | addHeaders(requestBuilder, headers); 17 | 18 | if (data != null) { 19 | requestBuilder = requestBuilder.method("DELETE", RequestBody.create(JSON_MEDIA_TYPE, data)); 20 | } 21 | 22 | Request request = requestBuilder.build(); 23 | 24 | try (Response response = client.newCall(request).execute()) { 25 | return response.body().string(); 26 | } catch (Exception e) { 27 | return "ERROR"; 28 | } 29 | } 30 | 31 | public static String sendGetRequest(String url, Map headers, Map params) { 32 | Request.Builder requestBuilder = new Request.Builder().url(buildUrlWithParams(url, params)).get(); 33 | 34 | addHeaders(requestBuilder, headers); 35 | 36 | Request request = requestBuilder.build(); 37 | 38 | try (Response response = client.newCall(request).execute()) { 39 | return response.body().string(); 40 | } catch (Exception e) { 41 | return "ERROR"; 42 | } 43 | } 44 | 45 | public static String sendPostRequest(String url, Map headers, String data, Map params, boolean isJson) { 46 | Request.Builder requestBuilder = new Request.Builder().url(buildUrlWithParams(url, params)); 47 | 48 | addHeaders(requestBuilder, headers); 49 | 50 | if (isJson) { 51 | requestBuilder = requestBuilder.post(RequestBody.create(JSON_MEDIA_TYPE, data)); 52 | } else { 53 | requestBuilder = requestBuilder.post(RequestBody.create(FORM_MEDIA_TYPE, data)); 54 | } 55 | 56 | Request request = requestBuilder.build(); 57 | 58 | try (Response response = client.newCall(request).execute()) { 59 | return response.body().string(); 60 | } catch (Exception e) { 61 | return "ERROR"; 62 | } 63 | } 64 | 65 | public static String sendPutRequest(String url, Map headers, String data, Map params) { 66 | Request.Builder requestBuilder = new Request.Builder().url(buildUrlWithParams(url, params)).put(RequestBody.create(JSON_MEDIA_TYPE, data)); 67 | 68 | addHeaders(requestBuilder, headers); 69 | 70 | Request request = requestBuilder.build(); 71 | 72 | try (Response response = client.newCall(request).execute()) { 73 | return response.body().string(); 74 | } catch (Exception e) { 75 | return "ERROR"; 76 | } 77 | } 78 | 79 | private static void addHeaders(Request.Builder requestBuilder, Map headers) { 80 | if (headers != null) { 81 | for (Map.Entry entry : headers.entrySet()) { 82 | requestBuilder.addHeader(entry.getKey(), entry.getValue()); 83 | } 84 | } 85 | } 86 | 87 | private static String buildUrlWithParams(String url, Map params) { 88 | if (params != null && !params.isEmpty()) { 89 | HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); 90 | for (Map.Entry entry : params.entrySet()) { 91 | urlBuilder.addQueryParameter(entry.getKey(), entry.getValue()); 92 | } 93 | return urlBuilder.build().toString(); 94 | } else { 95 | return url; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/util/MapList.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.util; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | 7 | public class MapList { 8 | public static Map search(List> mapList, String key, String value) { 9 | for (Map map : mapList) { 10 | if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 11 | return map; 12 | } 13 | } 14 | return null; 15 | } 16 | 17 | public static List> save(List> mapList, Map map, String key, String value) { 18 | boolean keyValuePairExists = mapList.stream().anyMatch(m -> value.equals(m.get(key))); 19 | 20 | if (keyValuePairExists) { 21 | mapList.removeIf(m -> value.equals(m.get(key))); 22 | } 23 | 24 | mapList.add(map); 25 | 26 | return mapList; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/net/tpcraft/minecraft/util/Moment.java: -------------------------------------------------------------------------------- 1 | package net.tpcraft.minecraft.util; 2 | 3 | import java.time.Instant; 4 | import java.time.LocalDateTime; 5 | import java.time.ZoneId; 6 | import java.time.format.DateTimeFormatter; 7 | 8 | public class Moment { 9 | public static String timestampToDate(Long timestamp) { 10 | Instant instant = Instant.ofEpochMilli(timestamp); 11 | LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("Asia/Shanghai")); 12 | DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 13 | 14 | return localDateTime.format(formatter); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # __________ ______ ______ ________ ___ ______ ___ __ __ # 3 | # /_ __/ __ \/ ____/________ _/ __/ /_/ _/ __ \/ | / ____/ / | __ __/ /_/ /_ # 4 | # / / / /_/ / / / ___/ __ `/ /_/ __// // / / / /| |/ / / /| |/ / / / __/ __ \ # 5 | # / / / ____/ /___/ / / /_/ / __/ /__/ // /_/ / ___ / /___ / ___ / /_/ / /_/ / / / # 6 | # /_/ /_/ \____/_/ \__,_/_/ \__/___/_____/_/ |_\____/ /_/ |_\__,_/\__/_/ /_/ # 7 | # # 8 | ######################################################################################## 9 | 10 | ################### 11 | # 注意事项 # 12 | ################### 13 | 14 | # 创建 OAuth2 应用 https://auth.tpcraft.net/oauth2/client 15 | # 如果域名未备案请使用IP作为回调地址 16 | 17 | ################### 18 | # 配置文件 # 19 | ################### 20 | 21 | # Web服务器端口 22 | webPort: 5900 23 | 24 | # OAuth2 25 | oauth2: 26 | clientId: '' # 标识 27 | clientSecret: '' # 密钥 28 | redirectUri: '' # 回调地址 29 | 30 | # 登入消息 31 | # 变量 %player%(玩家名称) 32 | loginMessage: 33 | enable: true # 是否启用 34 | join: '[&2+&r] &e%player%' # 进入消息 35 | leave: '[&4-&r] &e%player%' # 离开消息 36 | 37 | # 自动登入 38 | autoLogin: 39 | enable: false # 是否启用 40 | expires: 3600 # 超时时长(秒) 41 | 42 | # 固定登入坐标 43 | loginPosition: 44 | enable: false # 是否启用 45 | x: 0.0 # X轴 46 | y: 0.0 # Y轴 47 | z: 0.0 # Z轴 48 | 49 | # 白名单 50 | # 吐槽 原版白名单一点都不好用! 51 | whiteList: 52 | enable: false # 是否启用 53 | allowPlayers: [ ] # 白名单列表 -------------------------------------------------------------------------------- /src/main/resources/data/autoLoginData.yml: -------------------------------------------------------------------------------- 1 | players: [ ] -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: TPCraftIDACAuth 2 | version: '${project.version}' 3 | main: net.tpcraft.minecraft.TPCraftIDACAuth 4 | commands: 5 | auth: 6 | description: "TPCraftIDAC Auth 主命令" -------------------------------------------------------------------------------- /src/main/resources/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | TPCraftIDACAuth 7 | 46 | 47 | 48 |
49 |
50 | TPCraft Identity 51 | Authentication Center 52 |
53 |

TPCraft 身份认证中心

54 |

{{title}}

55 |
56 |
错误类型:{{error}}
57 |
错误原因:{{errorDescription}}
58 |
若出现此错误,您可以将此错误反馈给服务器管理员
59 |
60 |

您可以关闭此页面

61 |
62 | 63 | 64 | --------------------------------------------------------------------------------