From 9bc440d52687dfe135fe1789b687e5275a94e07f Mon Sep 17 00:00:00 2001 From: awaEric233 Date: Sat, 13 Jun 2026 18:31:53 +0800 Subject: [PATCH 1/3] =?UTF-8?q?Feat:=20=E6=B7=BB=E5=8A=A0=20Microsoft=20?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=BC=82=E5=B8=B8=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Authentication/MicrosoftAuthentication.cs | 25 +++++++++++++++++++ .../Authentication/GetTokenErrorResponse.cs | 15 +++++++++++ 2 files changed, 40 insertions(+) create mode 100644 Models/Authentication/GetTokenErrorResponse.cs diff --git a/Authentication/MicrosoftAuthentication.cs b/Authentication/MicrosoftAuthentication.cs index 945d28b..d7bf125 100644 --- a/Authentication/MicrosoftAuthentication.cs +++ b/Authentication/MicrosoftAuthentication.cs @@ -104,6 +104,31 @@ public async ValueTask GetTokenResponse(RetrieveDeviceCode dev ClientId = deviceCodeInfo.ClientId }; } + else + { + // 先判断是否正在等待中,直接使用 Contains,避免额外解析开销 + if (!tokenJson.Contains("authorization_pending")) + { + try + { + var errorData = tokenJson.ToJsonEntry(); + switch (errorData.Error) + { + case "authorization_declined": + throw new Exception("用户拒绝了授权"); + case "bad_verification_code": + throw new Exception("提交的 device_code 无效"); + case "expired_token": + throw new TimeoutException("登录已超时,请重试"); // 避免轮询时正好过期导致抓不到异常 + // 实际上还有其他的错误类型,但按理说不会出现,比如 slow_down + } + } + catch (Exception e) + { + throw new Exception("轮询获取 Token 错误:" + e.Message); + } + } + } await Task.Delay(pollingInterval); } diff --git a/Models/Authentication/GetTokenErrorResponse.cs b/Models/Authentication/GetTokenErrorResponse.cs new file mode 100644 index 0000000..d552a33 --- /dev/null +++ b/Models/Authentication/GetTokenErrorResponse.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace StarLight_Core.Models.Authentication; + +/// +/// 令牌错误信息 +/// +public class GetTokenErrorResponse +{ + /// + /// 验证令牌 + /// + [JsonPropertyName("error")] + public string Error { get; set; } +} \ No newline at end of file From 196dd045503520b8673984a4e750c91802a28cae Mon Sep 17 00:00:00 2001 From: awaEric233 Date: Sat, 13 Jun 2026 21:13:58 +0800 Subject: [PATCH 2/3] =?UTF-8?q?Revert=20"Feat:=20=E6=B7=BB=E5=8A=A0=20Micr?= =?UTF-8?q?osoft=20=E7=99=BB=E5=BD=95=E5=BC=82=E5=B8=B8=E6=A3=80=E6=B5=8B"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9bc440d52687dfe135fe1789b687e5275a94e07f. --- Authentication/MicrosoftAuthentication.cs | 25 ------------------- .../Authentication/GetTokenErrorResponse.cs | 15 ----------- 2 files changed, 40 deletions(-) delete mode 100644 Models/Authentication/GetTokenErrorResponse.cs diff --git a/Authentication/MicrosoftAuthentication.cs b/Authentication/MicrosoftAuthentication.cs index d7bf125..945d28b 100644 --- a/Authentication/MicrosoftAuthentication.cs +++ b/Authentication/MicrosoftAuthentication.cs @@ -104,31 +104,6 @@ public async ValueTask GetTokenResponse(RetrieveDeviceCode dev ClientId = deviceCodeInfo.ClientId }; } - else - { - // 先判断是否正在等待中,直接使用 Contains,避免额外解析开销 - if (!tokenJson.Contains("authorization_pending")) - { - try - { - var errorData = tokenJson.ToJsonEntry(); - switch (errorData.Error) - { - case "authorization_declined": - throw new Exception("用户拒绝了授权"); - case "bad_verification_code": - throw new Exception("提交的 device_code 无效"); - case "expired_token": - throw new TimeoutException("登录已超时,请重试"); // 避免轮询时正好过期导致抓不到异常 - // 实际上还有其他的错误类型,但按理说不会出现,比如 slow_down - } - } - catch (Exception e) - { - throw new Exception("轮询获取 Token 错误:" + e.Message); - } - } - } await Task.Delay(pollingInterval); } diff --git a/Models/Authentication/GetTokenErrorResponse.cs b/Models/Authentication/GetTokenErrorResponse.cs deleted file mode 100644 index d552a33..0000000 --- a/Models/Authentication/GetTokenErrorResponse.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; - -namespace StarLight_Core.Models.Authentication; - -/// -/// 令牌错误信息 -/// -public class GetTokenErrorResponse -{ - /// - /// 验证令牌 - /// - [JsonPropertyName("error")] - public string Error { get; set; } -} \ No newline at end of file From 412929a10a8609106efa99cce24bafc6daceed29 Mon Sep 17 00:00:00 2001 From: awaEric233 Date: Sat, 13 Jun 2026 21:59:25 +0800 Subject: [PATCH 3/3] =?UTF-8?q?Feat:=20=E8=B4=A6=E6=88=B7=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8A=9F=E8=83=BD=E6=B7=BB=E5=8A=A0=E3=80=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Authentication/MicrosoftAuthentication.cs | 31 ++++++++++++- .../Authentication/GetTokenErrorResponse.cs | 16 +++++++ Skin/Fetchers/MicrosoftSkinFetcher.cs | 12 +++++ Skin/Fetchers/YggdrasilSkinFetcher.cs | 45 +++++++++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 Models/Authentication/GetTokenErrorResponse.cs create mode 100644 Skin/Fetchers/YggdrasilSkinFetcher.cs diff --git a/Authentication/MicrosoftAuthentication.cs b/Authentication/MicrosoftAuthentication.cs index 945d28b..2cf28fe 100644 --- a/Authentication/MicrosoftAuthentication.cs +++ b/Authentication/MicrosoftAuthentication.cs @@ -104,6 +104,33 @@ public async ValueTask GetTokenResponse(RetrieveDeviceCode dev ClientId = deviceCodeInfo.ClientId }; } + else + { + // 先判断是否正在等待中,直接使用 Contains,避免额外解析开销 + if (!tokenJson.Contains("authorization_pending")) + { + try + { + var errorData = tokenJson.ToJsonEntry(); + switch (errorData.Error) + { + case "authorization_declined": + throw new Exception("用户拒绝了授权"); + case "bad_verification_code": + throw new Exception("提交的 device_code 无效"); + case "expired_token": + throw new Exception("登录已超时,请重试"); // 避免轮询时正好过期导致抓不到异常 + default: + throw new Exception(errorData.Error); + // 实际上还有其他的错误类型,但按理说不会出现,比如 slow_down + } + } + catch (Exception e) + { + throw new Exception("轮询获取 Token 错误:" + e.Message); + } + } + } await Task.Delay(pollingInterval); } @@ -124,7 +151,7 @@ public async ValueTask MicrosoftAuthAsync(GetTokenResponse tok string? refreshToken = null) { if (refreshToken == null) return await GetMicrosoftAuthInfo(tokenInfo, action); - + // 刷新令牌 action("正在刷新令牌"); @@ -270,7 +297,7 @@ public async ValueTask GetMicrosoftAuthInfo(GetTokenResponse t var minecraftProfile = profileContent.ToJsonEntry(); if (minecraftProfile == null) throw new Exception("验证失败"); - + var uuid = minecraftProfile.Uuid; var name = minecraftProfile.Name; var skinUrl = minecraftProfile.Skins[0].Url; diff --git a/Models/Authentication/GetTokenErrorResponse.cs b/Models/Authentication/GetTokenErrorResponse.cs new file mode 100644 index 0000000..ded04c3 --- /dev/null +++ b/Models/Authentication/GetTokenErrorResponse.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace StarLight_Core.Models.Authentication; + +/// +/// 令牌错误信息 +/// +/// 查看文档 +public class GetTokenErrorResponse +{ + /// + /// 错误 + /// + [JsonPropertyName("error")] + public string Error { get; set; } +} \ No newline at end of file diff --git a/Skin/Fetchers/MicrosoftSkinFetcher.cs b/Skin/Fetchers/MicrosoftSkinFetcher.cs index bbd068b..f942f5a 100644 --- a/Skin/Fetchers/MicrosoftSkinFetcher.cs +++ b/Skin/Fetchers/MicrosoftSkinFetcher.cs @@ -1,4 +1,5 @@ using System.Text; +using StarLight_Core.Models.Authentication; using StarLight_Core.Models.Skin; using StarLight_Core.Utilities; @@ -9,6 +10,16 @@ namespace StarLight_Core.Skin.Fetchers; /// public class MicrosoftSkinFetcher { + /// + /// 获取微软皮肤 + /// + /// 皮肤图片字节信息 + /// 皮肤图片字节信息 + public static async Task GetMicrosoftSkinAsync(MicrosoftAccount account) + { + return await GetMicrosoftSkinAsync(account.Uuid); + } + /// /// 获取微软皮肤 /// @@ -17,6 +28,7 @@ public class MicrosoftSkinFetcher public static async Task GetMicrosoftSkinAsync(string uuid) { const string baseUrl = "https://sessionserver.mojang.com/session/minecraft/profile/"; + uuid = uuid.Replace("-", ""); var skinJson = await HttpUtil.GetStringAsync(baseUrl + uuid); var skinUrl = Encoding.UTF8.GetString( diff --git a/Skin/Fetchers/YggdrasilSkinFetcher.cs b/Skin/Fetchers/YggdrasilSkinFetcher.cs new file mode 100644 index 0000000..5d622e2 --- /dev/null +++ b/Skin/Fetchers/YggdrasilSkinFetcher.cs @@ -0,0 +1,45 @@ +using StarLight_Core.Models.Authentication; +using StarLight_Core.Models.Skin; +using StarLight_Core.Utilities; +using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; +using System.Text; + +namespace StarLight_Core.Skin.Fetchers; + +/// +/// 外置皮肤获取器 +/// +public class YggdrasilSkinFetcher +{ + /// + /// 获取外置皮肤 + /// + /// 外置账户 + /// 皮肤图片字节信息 + public static async Task GetYggdrasilSkinAsync(YggdrasilAccount account) + { + return await GetYggdrasilSkinAsync(account.ServerUrl, account.Uuid); + } + + /// + /// 获取外置皮肤 + /// + /// 服务器 Url + /// 外置账户 Uuid + /// 皮肤图片字节信息 + public static async Task GetYggdrasilSkinAsync(string serverUrl, string uuid) + { + var baseUrl = serverUrl.TrimEnd("/"); + uuid = uuid.Replace("-", ""); + var skinJson = await HttpUtil.GetStringAsync($"{baseUrl}/sessionserver/session/minecraft/profile/{uuid}"); + var skinUrl = + Encoding.UTF8.GetString( + Convert.FromBase64String( + skinJson.ToJsonEntry().Properties.First().Value)) + .ToJsonEntry() + .Textures.Skin.Url; + using var httpClient = new HttpClient(); + return await httpClient.GetByteArrayAsync(skinUrl); + } +} \ No newline at end of file