fix(login): 修复正版账号皮肤获取与登录刷新异常 (#2947)#2951
Merged
LuLu-ling merged 1 commit intoMay 31, 2026
Merged
Conversation
审阅者指南(在小型 PR 上默认折叠)审阅者指南修复从 Newtonsoft.Json 迁移到 System.Text.Json 时引入的回归问题,这些问题导致微软账号皮肤获取和基于刷新令牌的登录失效,并通过收紧 JSON 处理、错误传播以及令牌重置逻辑,解决潜在的无限重新登录循环。 皮肤获取 JSON 处理修复的时序图sequenceDiagram
participant McSkinGetAddress
participant ModNet
participant ModBase
McSkinGetAddress->>ModNet: NetGetCodeByRequestOnce(url, Encode, Timeout, IsJson=false)
ModNet->>ModNet: result = Requester.FetchString(url, param)
ModNet->>ModBase: GetJson(result)
ModNet-->>McSkinGetAddress: (object)result
McSkinGetAddress->>McSkinGetAddress: skinString = (string)returnValue
OAuth 刷新令牌及重新登录处理的时序图sequenceDiagram
participant GetOAuthTokens
participant MsLoginStep1Refresh
participant Requester
actor User
loop login_attempt
GetOAuthTokens->>MsLoginStep1Refresh: MsLoginStep1Refresh(OAuthRefreshToken)
MsLoginStep1Refresh->>Requester: Send refresh request
Requester-->>MsLoginStep1Refresh: response
MsLoginStep1Refresh->>MsLoginStep1Refresh: Result = response.AsString()
alt !response.IsSuccess
MsLoginStep1Refresh-->>GetOAuthTokens: [throws HttpRequestException with body]
else response.IsSuccess
MsLoginStep1Refresh-->>GetOAuthTokens: tokens
end
alt tokens[0] == Relogin
GetOAuthTokens->>GetOAuthTokens: OAuthRefreshToken = ""
GetOAuthTokens-->>GetOAuthTokens: continue loop (device code flow)
else tokens[0] == Ignore
GetOAuthTokens-->>GetOAuthTokens: handle ignore
else user_cancels
User-->>MsLoginStep1Refresh: cancel login
MsLoginStep1Refresh-->>GetOAuthTokens: [throws Exception "$$"]
end
end
文件级变更
可能关联的问题
提示与命令与 Sourcery 交互
自定义你的使用体验访问你的 控制面板 来:
获取帮助Original review guide in EnglishReviewer's guide (collapsed on small PRs)Reviewer's GuideFixes regressions introduced by the Newtonsoft.Json → System.Text.Json migration that broke Microsoft account skin retrieval and token refresh-based login, and addresses a potential infinite relogin loop by tightening JSON handling, error propagation, and token reset logic. Sequence diagram for skin retrieval JSON handling fixsequenceDiagram
participant McSkinGetAddress
participant ModNet
participant ModBase
McSkinGetAddress->>ModNet: NetGetCodeByRequestOnce(url, Encode, Timeout, IsJson=false)
ModNet->>ModNet: result = Requester.FetchString(url, param)
ModNet->>ModBase: GetJson(result)
ModNet-->>McSkinGetAddress: (object)result
McSkinGetAddress->>McSkinGetAddress: skinString = (string)returnValue
Sequence diagram for OAuth token refresh and relogin handlingsequenceDiagram
participant GetOAuthTokens
participant MsLoginStep1Refresh
participant Requester
actor User
loop login_attempt
GetOAuthTokens->>MsLoginStep1Refresh: MsLoginStep1Refresh(OAuthRefreshToken)
MsLoginStep1Refresh->>Requester: Send refresh request
Requester-->>MsLoginStep1Refresh: response
MsLoginStep1Refresh->>MsLoginStep1Refresh: Result = response.AsString()
alt !response.IsSuccess
MsLoginStep1Refresh-->>GetOAuthTokens: [throws HttpRequestException with body]
else response.IsSuccess
MsLoginStep1Refresh-->>GetOAuthTokens: tokens
end
alt tokens[0] == Relogin
GetOAuthTokens->>GetOAuthTokens: OAuthRefreshToken = ""
GetOAuthTokens-->>GetOAuthTokens: continue loop (device code flow)
else tokens[0] == Ignore
GetOAuthTokens-->>GetOAuthTokens: handle ignore
else user_cancels
User-->>MsLoginStep1Refresh: cancel login
MsLoginStep1Refresh-->>GetOAuthTokens: [throws Exception "$$"]
end
end
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - 我在这里提供了一些总体反馈:
- 使用
throw new Exception("$$")作为控制流信号既脆弱又不清晰;建议引入一个专门的异常类型,或者使用一个命名清晰的常量 / 枚举 / 结果码,这样调用方就可以可靠地区分这条执行路径,而不必依赖魔法字符串。 MsLoginStep1Refresh中的错误分类依赖于对本地化 / 远程错误消息的子串检查(例如invalid_grant、must first sign in);如果可能,优先检查响应 JSON 中的结构化字段,比如状态码或错误码,以便让这段逻辑在错误消息文本变更时更加健壮。
给 AI 代理的提示
Please address the comments from this code review:
## Overall Comments
- Using `throw new Exception("$$")` as a control-flow signal is brittle and unclear; consider introducing a dedicated exception type or a well-named constant/enum/result code so callers can reliably distinguish this path without depending on a magic string.
- The error classification in `MsLoginStep1Refresh` relies on substring checks of localized/remote error messages (e.g., `invalid_grant`, `must first sign in`); if possible, prefer checking structured fields such as status codes or error codes from the response JSON to make the logic more robust to message text changes.帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的评审。
Original comment in English
Hey - I've left some high level feedback:
- Using
throw new Exception("$$")as a control-flow signal is brittle and unclear; consider introducing a dedicated exception type or a well-named constant/enum/result code so callers can reliably distinguish this path without depending on a magic string. - The error classification in
MsLoginStep1Refreshrelies on substring checks of localized/remote error messages (e.g.,invalid_grant,must first sign in); if possible, prefer checking structured fields such as status codes or error codes from the response JSON to make the logic more robust to message text changes.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Using `throw new Exception("$$")` as a control-flow signal is brittle and unclear; consider introducing a dedicated exception type or a well-named constant/enum/result code so callers can reliably distinguish this path without depending on a magic string.
- The error classification in `MsLoginStep1Refresh` relies on substring checks of localized/remote error messages (e.g., `invalid_grant`, `must first sign in`); if possible, prefer checking structured fields such as status codes or error codes from the response JSON to make the logic more robust to message text changes.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Contributor
|
如果是由 AI 辅助的 PR,记得在 Description 里标注一下模型名称 |
Contributor
Author
收到,已标注名称 |
lhx077
previously approved these changes
May 31, 2026
Member
|
conflicts |
7b0275a to
71422de
Compare
LuLu-ling
approved these changes
May 31, 2026
lhx077
approved these changes
May 31, 2026
System.Text.Json 迁移后引入的两处回归: - ModNet.NetGetCodeByRequestRetry/Once 中三元表达式因 string→JsonNode 隐式转换被统一为 JsonNode,导致非 JSON 分支也被包装成 JsonValuePrimitive<string>,皮肤解析处 (string) 强转抛 InvalidCastException。将 JSON 分支显式转为 object 以保留各分支原类型。 - MsLoginStep1Refresh 中 EnsureSuccessStatusCode 绑定到内置方法,抛出的 异常不含响应体,使 invalid_grant 等失效令牌检测失效;用户取消后落入 GetJson(null) 抛出空引用。改为先读取响应体再抛出携带正文的异常, 补充 invalid_grant 检测,并在取消时以 "$$" 静默中止。 - GetOAuthTokens 在 Relogin 时未清空 OAuthRefreshToken 导致无限循环, 现清空后回退至设备代码流。
71422de to
df430c3
Compare
Contributor
Author
|
终于签上了喵 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 Issue
fix #2947:正版账号皮肤无法获取、正版游戏无法登录。
问题原因
两处问题均为
Newtonsoft.Json→System.Text.Json迁移(#2931)后引入的回归。1. 皮肤无法获取(
InvalidCastException)ModNet.NetGetCodeByRequestRetry/NetGetCodeByRequestOnce中:GetJson返回JsonNode,而result为string。System.Text.Json定义了string→JsonNode的隐式转换,因此编译器将三元表达式的两个分支统一为JsonNode——即便IsJson = false,原始字符串也会被包装成JsonValuePrimitive<string>。调用方McSkinGetAddress随后执行(string)skinString时便抛出InvalidCastException。Newtonsoft.Json没有这一隐式转换,故迁移前正常。对应日志:
2. 正版无法登录(
ArgumentNullException)MsLoginStep1Refresh中刷新令牌请求返回400时,response.EnsureSuccessStatusCode()绑定到了内置方法(实例方法优先于扩展方法),其抛出的异常不包含响应体,导致invalid_grant/must sign in again等"令牌失效"判定全部落空。用户点击取消后,代码继续向下执行至GetJson(Result),而此时Result为null,最终抛出令人费解的"格式化 JSON 失败 / Value cannot be null"。对应日志:
3.
Relogin无限循环(潜在缺陷)GetOAuthTokens在MsLoginStep1Refresh返回"Relogin"时直接continue,但未清空input.OAuthRefreshToken,导致再次进入刷新分支,形成无限循环。修改内容
ModNet.cs:将三元表达式的 JSON 分支显式转换为object(IsJson ? (object)ModBase.GetJson(result) : result),使非 JSON 分支保留原始string类型。同时修复NetGetCodeByRequestRetry与NetGetCodeByRequestOnce。ModLaunch.cs·MsLoginStep1Refresh:先读取响应体,再抛出携带正文的HttpRequestException;补充invalid_grant/must first sign in检测;用户取消时以"$$"静默中止启动,避免落入GetJson(null)空引用。ModLaunch.cs·GetOAuthTokens:Relogin时清空OAuthRefreshToken,回退至设备代码流,避免无限循环。测试情况
dotnet build:0 个 C# 编译错误(仅因启动器正在运行导致输出.exe被占用的文件锁错误,与本次改动无关)。Summary by Sourcery
修复由于 JSON 处理和令牌刷新回归导致的 Microsoft 账号登录和皮肤获取问题。
Bug 修复:
InvalidCastException而出错。增强:
Original summary in English
Summary by Sourcery
Fix issues with Microsoft account login and skin retrieval caused by JSON handling and token refresh regressions.
Bug Fixes:
Enhancements: