feat(account): OAuth account relogin.

This commit is contained in:
huanghongxun
2021-10-12 22:00:41 +08:00
parent 948d64237e
commit 23c2c0689c
13 changed files with 209 additions and 43 deletions

View File

@@ -24,13 +24,7 @@ import javafx.beans.property.ReadOnlyListWrapper;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.AccountFactory;
import org.jackhuang.hmcl.auth.AuthenticationException;
import org.jackhuang.hmcl.auth.CharacterDeletedException;
import org.jackhuang.hmcl.auth.NoCharacterException;
import org.jackhuang.hmcl.auth.ServerDisconnectException;
import org.jackhuang.hmcl.auth.ServerResponseMalformedException;
import org.jackhuang.hmcl.auth.*;
import org.jackhuang.hmcl.auth.authlibinjector.*;
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccountFactory;
@@ -382,6 +376,8 @@ public final class Accounts {
return i18n("account.methods.microsoft.error.add_family_probably");
} else if (exception instanceof MicrosoftAuthenticationServer.MicrosoftAuthenticationNotSupportedException) {
return i18n("account.methods.microsoft.snapshot");
} else if (exception instanceof OAuthAccount.WrongAccountException) {
return i18n("account.failed.wrong_account");
} else if (exception.getClass() == AuthenticationException.class) {
return exception.getLocalizedMessage();
} else {

View File

@@ -17,12 +17,9 @@
*/
package org.jackhuang.hmcl.ui;
import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.auth.AuthenticationException;
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
import org.jackhuang.hmcl.ui.account.AccountLoginWithPasswordDialog;
import org.jackhuang.hmcl.auth.*;
import org.jackhuang.hmcl.ui.account.ClassicAccountLoginDialog;
import org.jackhuang.hmcl.ui.account.OAuthAccountLoginDialog;
import java.util.Optional;
import java.util.concurrent.CancellationException;
@@ -36,11 +33,23 @@ public final class DialogController {
}
public static AuthInfo logIn(Account account) throws CancellationException, AuthenticationException, InterruptedException {
if (account instanceof YggdrasilAccount) {
if (account instanceof ClassicAccount) {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<AuthInfo> res = new AtomicReference<>(null);
runInFX(() -> {
AccountLoginWithPasswordDialog pane = new AccountLoginWithPasswordDialog(account, it -> {
ClassicAccountLoginDialog pane = new ClassicAccountLoginDialog((ClassicAccount) account, it -> {
res.set(it);
latch.countDown();
}, latch::countDown);
Controllers.dialog(pane);
});
latch.await();
return Optional.ofNullable(res.get()).orElseThrow(CancellationException::new);
} else if (account instanceof OAuthAccount) {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<AuthInfo> res = new AtomicReference<>(null);
runInFX(() -> {
OAuthAccountLoginDialog pane = new OAuthAccountLoginDialog((OAuthAccount) account, it -> {
res.set(it);
latch.countDown();
}, latch::countDown);
@@ -48,8 +57,6 @@ public final class DialogController {
});
latch.await();
return Optional.ofNullable(res.get()).orElseThrow(CancellationException::new);
} else if (account instanceof MicrosoftAccount) {
}
return account.logIn();
}

View File

@@ -27,8 +27,8 @@ import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.auth.Account;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.auth.ClassicAccount;
import org.jackhuang.hmcl.auth.NoSelectedCharacterException;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
@@ -48,8 +48,8 @@ import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class AccountLoginWithPasswordDialog extends StackPane {
private final Account oldAccount;
public class ClassicAccountLoginDialog extends StackPane {
private final ClassicAccount oldAccount;
private final Consumer<AuthInfo> success;
private final Runnable failed;
@@ -57,7 +57,7 @@ public class AccountLoginWithPasswordDialog extends StackPane {
private final Label lblCreationWarning = new Label();
private final JFXProgressBar progressBar;
public AccountLoginWithPasswordDialog(Account oldAccount, Consumer<AuthInfo> success, Runnable failed) {
public ClassicAccountLoginDialog(ClassicAccount oldAccount, Consumer<AuthInfo> success, Runnable failed) {
this.oldAccount = oldAccount;
this.success = success;
this.failed = failed;

View File

@@ -0,0 +1,86 @@
package org.jackhuang.hmcl.ui.account;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.auth.AuthInfo;
import org.jackhuang.hmcl.auth.OAuthAccount;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
import org.jackhuang.hmcl.game.MicrosoftAuthenticationServer;
import org.jackhuang.hmcl.setting.Accounts;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import java.util.function.Consumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class OAuthAccountLoginDialog extends DialogPane {
private final OAuthAccount account;
private final Consumer<AuthInfo> success;
private final Runnable failed;
private final BooleanProperty logging = new SimpleBooleanProperty();
public OAuthAccountLoginDialog(OAuthAccount account, Consumer<AuthInfo> success, Runnable failed) {
this.account = account;
this.success = success;
this.failed = failed;
setTitle(i18n("account.login.refresh"));
VBox vbox = new VBox(8);
Label usernameLabel = new Label(account.getUsername());
HintPane hintPane = new HintPane(MessageDialogPane.MessageType.INFO);
hintPane.textProperty().bind(BindingMapping.of(logging).map(logging ->
logging
? i18n("account.methods.microsoft.manual")
: i18n("account.methods.microsoft.hint")));
hintPane.setOnMouseClicked(e -> {
if (logging.get() && MicrosoftAuthenticationServer.lastlyOpenedURL != null) {
FXUtils.copyText(MicrosoftAuthenticationServer.lastlyOpenedURL);
}
});
HBox box = new HBox(8);
JFXHyperlink birthLink = new JFXHyperlink(i18n("account.methods.microsoft.birth"));
birthLink.setOnAction(e -> FXUtils.openLink("https://support.microsoft.com/zh-cn/account-billing/如何更改-microsoft-帐户上的出生日期-837badbc-999e-54d2-2617-d19206b9540a"));
JFXHyperlink profileLink = new JFXHyperlink(i18n("account.methods.microsoft.profile"));
profileLink.setOnAction(e -> FXUtils.openLink("https://account.live.com/editprof.aspx"));
JFXHyperlink purchaseLink = new JFXHyperlink(i18n("account.methods.yggdrasil.purchase"));
purchaseLink.setOnAction(e -> FXUtils.openLink(YggdrasilService.PURCHASE_URL));
box.getChildren().setAll(profileLink, birthLink, purchaseLink);
GridPane.setColumnSpan(box, 2);
vbox.getChildren().setAll(usernameLabel, hintPane, box);
setBody(vbox);
}
@Override
protected void onAccept() {
setLoading();
Task.supplyAsync(account::logInWhenCredentialsExpired)
.whenComplete(Schedulers.javafx(), authInfo -> {
success.accept(authInfo);
onSuccess();
}, e -> {
LOG.log(Level.INFO, "Failed to login when credentials expired: " + account, e);
onFailure(Accounts.localizeErrorMessage(e));
}).start();
}
@Override
protected void onCancel() {
failed.run();
super.onCancel();
}
}

View File

@@ -70,6 +70,7 @@ account.failed.invalid_token=Please log out and re-enter your password to login.
account.failed.migration=Your account needs to be migrated to a Microsoft account. If already migrated, you should login your migrated Microsoft account instead.
account.failed.no_character=No character in this account.
account.failed.server_response_malformed=Invalid server response. The authentication server may have an error.
account.failed.wrong_account=Logged in with mismatched account.
account.injector.add=Add an authentication server
account.injector.empty=Empty (Click the plus button on the right to add)
account.injector.http=Warning: This server uses HTTP so your password will be transmitted in clear text.
@@ -79,6 +80,7 @@ account.injector.server_url=Server URL
account.injector.server_name=Server Name
account.login=Login
account.login.hint=We will not save your password.
account.login.refresh=Re-log in
account.logout=Logout
account.register=Register
account.manage=Account List

View File

@@ -70,6 +70,7 @@ account.failed.invalid_token=請嘗試登出並重新輸入密碼登入
account.failed.migration=你的帳號需要被遷移至微軟帳號。如果你已經遷移,你需要使用微軟登錄方式登錄遷移後的微軟帳號。
account.failed.no_character=該帳戶沒有角色
account.failed.server_response_malformed=無法解析認證伺服器回應,可能是伺服器故障
account.failed.wrong_account=登錄了錯誤的帳號
account.injector.add=新增認證伺服器
account.injector.empty=無 (按一下右側 + 加入)
account.injector.http=警告: 此伺服器使用不安全的 HTTP 協定,您的密碼在登入時會被明文傳輸。
@@ -79,6 +80,7 @@ account.injector.server_url=伺服器位址
account.injector.server_name=伺服器名稱
account.login=登入
account.login.hint=我們不會保存你的密碼
account.login.refresh=重新登錄
account.logout=登出
account.register=註冊
account.manage=帳戶列表

View File

@@ -70,6 +70,7 @@ account.failed.invalid_token=请尝试登出并重新输入密码登录
account.failed.migration=你的帐号需要被迁移至微软帐号。如果你已经迁移,你需要使用微软登录方式登录迁移后的微软帐号。
account.failed.no_character=该帐号没有角色
account.failed.server_response_malformed=无法解析认证服务器响应,可能是服务器故障
account.failed.wrong_account=登录了错误的帐号
account.injector.add=添加认证服务器
account.injector.empty=无(点击右侧加号添加)
account.injector.http=警告:此服务器使用不安全的 HTTP 协议,您的密码在登录时会被明文传输。
@@ -79,6 +80,7 @@ account.injector.server_url=服务器地址
account.injector.server_name=服务器名称
account.login=登录
account.login.hint=我们不会保存你的密码
account.login.refresh=重新登录
account.logout=登出
account.register=注册
account.manage=帐户列表