-
Notifications
You must be signed in to change notification settings - Fork 818
feat: 支持使用 AUTHORIZATION_CODE 验证流 #5330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
「复制链接并打开浏览器」我只看到了浏览器出现,但剪贴板没有新的东西。 |
Co-authored-by: 3gf8jv4dv <3gf8jv4dv@gmail.com>
|
此 PR 若未添加 OAuth 信息,可能会导致进入此界面后无法退出当前对话框 请考虑像 #5297 添加一个警告信息,并提供按钮能够让用户返回 |
|
注意到 Prism Launcher 的逻辑是二维码包含登录所需的代码,内容为 如果要比较,Prism Launcher 的体验相对会更好,但如果 HMCL 也这么干,则需要引入一个二维码生成库例如 ZXing (Apache 2.0) 或者 nayuki/QR-Code-generator (MIT) ,是否有必要在这一方面进行取舍 🤔 |
可以分成两步实现,这个 PR 先专心更新到授权代码流,其他部分我之后研究一下。二维码库我之前就在考虑引入了。 |
|
|
| account.methods.microsoft.manual=If the website fails to load, please visit %s manually in your browser.\n\ | ||
| \n\ | ||
| <b>If your internet connection is bad, it may cause web pages to load slowly or fail to load altogether. You may try again later or switch to a different internet connection.</b> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| account.methods.microsoft.manual=If the website fails to load, please visit %s manually in your browser.\n\ | |
| \n\ | |
| <b>If your internet connection is bad, it may cause web pages to load slowly or fail to load altogether. You may try again later or switch to a different internet connection.</b> | |
| account.methods.microsoft.manual=<b>If your internet connection is bad, it may cause web pages to load slowly or fail to load altogether.\nYou may try again later or switch to a different internet connection.</b> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for the AUTHORIZATION_CODE authentication flow for Microsoft accounts alongside the existing DEVICE flow, improving the user experience by offering a more streamlined browser-based login option while maintaining the device code flow for cross-device scenarios. This implementation is inspired by PrismLauncher's approach.
Changes:
- Added dual authentication flow support (AUTHORIZATION_CODE and DEVICE) with concurrent execution
- Replaced OAuthAccountLoginDialog with a new MicrosoftAccountLoginPane that displays both login options
- Updated HTML success page with modern styling using the application's theme system
- Enhanced localization strings to support the new two-flow UI
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| HMCLCore/src/main/java/org/jackhuang/hmcl/auth/OAuth.java | Added flow type parameter to openBrowser callback to differentiate between flows |
| HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java | Modified authenticate method to accept OAuth.GrantFlow parameter |
| HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftAccount.java | Updated constructor to use GrantFlow instead of CharacterSelector |
| HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftAccountFactory.java | Changed create method to pass GrantFlow from additionalData parameter |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/account/MicrosoftAccountLoginPane.java | New dialog that runs both auth flows concurrently and displays both login options |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OAuthAccountLoginDialog.java | Removed old single-flow login dialog |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/account/CreateAccountPane.java | Updated to use new MicrosoftAccountLoginPane |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java | Updated to use new MicrosoftAccountLoginPane |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/DialogController.java | Updated to use new MicrosoftAccountLoginPane for credential refresh |
| HMCL/src/main/java/org/jackhuang/hmcl/game/OAuthServer.java | Split openBrowser events into separate handlers for each flow type |
| HMCL/src/main/resources/assets/microsoft_auth.html | Enhanced success page with modern Material Design styling |
| HMCL/src/main/resources/assets/lang/*.properties | Added localization for new two-flow login interface |
| HMCL/src/main/resources/assets/img/microsoft_login.png | Added QR code placeholder image for device flow |
| HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java | Minor whitespace formatting |
Comments suppressed due to low confidence (1)
HMCL/src/main/java/org/jackhuang/hmcl/ui/account/MicrosoftAccountLoginPane.java:329
- Extra blank line at the end of the file. The file should end with a single newline character.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService; | ||
| import org.jackhuang.hmcl.util.javafx.BindingMapping; | ||
|
|
||
| import java.awt.*; |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import 'java.awt.*' should be removed. This import was added but is not used anywhere in the file.
| import java.awt.*; |
| lblErrorMessage.setText(""); | ||
| lblErrorMessage.setVisible(true); | ||
| actions.setVisible(true); | ||
| actions.setVisible(true); |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate line: 'actions.setVisible(false);' is called twice consecutively. One of these lines should be removed.
| actions.setVisible(true); |
|
|
||
| import org.jackhuang.hmcl.auth.AccountFactory; | ||
| import org.jackhuang.hmcl.auth.AuthenticationException; | ||
| import org.jackhuang.hmcl.auth.CharacterSelector; |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import 'org.jackhuang.hmcl.auth.CharacterSelector' is no longer used in this file and should be removed. The CharacterSelector parameter was replaced with OAuth.GrantFlow in the create method.
| ExceptionalConsumer<Exception, Exception> onFail = (e) -> runInFX(() -> { | ||
| if (!(e instanceof CancellationException)) { | ||
| errHintPane.setText(Accounts.localizeErrorMessage(e)); | ||
| errHintPane.setVisible(true); | ||
| authMethodsContentBox.setVisible(false); | ||
| loginButtonSpinner.hideSpinner(); | ||
| } | ||
| }); |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error handler doesn't hide the spinner when a CancellationException occurs. While this might be intentional (since the tasks are being cancelled), it could leave the UI in an inconsistent state if cancelAllTasks is called while an error is being displayed. Consider explicitly hiding the spinner in the cancelAllTasks method to ensure consistent UI state.
| } catch (AuthenticationException e) { | ||
| errHintPane.setText(Accounts.localizeErrorMessage(e)); | ||
| errHintPane.setVisible(true); | ||
| loginButtonSpinner.showSpinner(); |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error handling issue: When loginCallback.accept(account.logIn()) throws an AuthenticationException on line 306, the code sets errHintPane visibility to true and shows the spinner on line 310, but it doesn't call cancelAllTasks(). This means the other background task (browser or device) continues running unnecessarily. Consider calling cancelAllTasks() before returning to clean up properly.
| loginButtonSpinner.showSpinner(); | |
| loginButtonSpinner.showSpinner(); | |
| cancelAllTasks(); |
| * @param authorizationCode | ||
| * @param url OAuth url. | ||
| */ | ||
| void openBrowser(String url) throws IOException; | ||
| void openBrowser(GrantFlow authorizationCode, String url) throws IOException; |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter name 'authorizationCode' is misleading. It should be named 'grantFlow' or 'flow' since it represents the type of grant flow being used (AUTHORIZATION_CODE or DEVICE), not an actual authorization code value. This makes the API confusing for developers who might expect this to be a code string.
| browserTaskExecuter = Task.supplyAsync(() -> Accounts.FACTORY_MICROSOFT.create(null, null, null, null, OAuth.GrantFlow.AUTHORIZATION_CODE)) | ||
| .whenComplete(Schedulers.javafx(), onSuccess, onFail) | ||
| .executor(true); | ||
|
|
||
| deviceTaskExecuter = Task.supplyAsync(() -> Accounts.FACTORY_MICROSOFT.create(null, null, null, null, OAuth.GrantFlow.DEVICE)) | ||
| .whenComplete(Schedulers.javafx(), onSuccess, onFail) | ||
| .executor(true); | ||
| } |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential race condition: When either browser or device flow succeeds, it cancels all tasks and calls onLoginCompleted. However, if both flows complete nearly simultaneously, onLoginCompleted could be called twice. The second call might interfere with account management operations. Consider adding a flag to ensure onLoginCompleted is only executed once, or synchronize access to prevent concurrent execution.
| vbox.getChildren().addAll(new MicrosoftAccountLoginPane(true)); | ||
| btnAccept.setOnAction(e -> { | ||
| fireEvent(new DialogCloseEvent()); | ||
| Controllers.dialog(new MicrosoftAccountLoginPane()); | ||
| }); |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Microsoft account creation flow creates a MicrosoftAccountLoginPane with bodyonly=true and embeds it in the CreateAccountPane, but then the btnAccept action closes the CreateAccountPane and opens a new full MicrosoftAccountLoginPane dialog. This creates a confusing UX where users see a preview/hint of the login interface, then clicking "Log in" closes that dialog and opens a new one with the actual login functionality. Consider either showing the full functional login pane directly in CreateAccountPane, or removing the embedded preview pane to avoid confusion.


Resolves #5135


界面参考自 PrismLauncher