feat(microsoft): WIP: handle credentials expiration.

This commit is contained in:
huanghongxun
2021-10-12 14:04:18 +08:00
parent 28278c091d
commit 3433e88bb8
4 changed files with 53 additions and 8 deletions

View File

@@ -20,8 +20,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.AccountLoginPane;
import org.jackhuang.hmcl.ui.account.AccountLoginWithPasswordDialog;
import java.util.Optional;
import java.util.concurrent.CancellationException;
@@ -39,7 +40,7 @@ public final class DialogController {
CountDownLatch latch = new CountDownLatch(1);
AtomicReference<AuthInfo> res = new AtomicReference<>(null);
runInFX(() -> {
AccountLoginPane pane = new AccountLoginPane(account, it -> {
AccountLoginWithPasswordDialog pane = new AccountLoginWithPasswordDialog(account, it -> {
res.set(it);
latch.countDown();
}, latch::countDown);
@@ -47,6 +48,8 @@ public final class DialogController {
});
latch.await();
return Optional.ofNullable(res.get()).orElseThrow(CancellationException::new);
} else if (account instanceof MicrosoftAccount) {
}
return account.logIn();
}

View File

@@ -48,7 +48,7 @@ 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 AccountLoginPane extends StackPane {
public class AccountLoginWithPasswordDialog extends StackPane {
private final Account oldAccount;
private final Consumer<AuthInfo> success;
private final Runnable failed;
@@ -57,7 +57,7 @@ public class AccountLoginPane extends StackPane {
private final Label lblCreationWarning = new Label();
private final JFXProgressBar progressBar;
public AccountLoginPane(Account oldAccount, Consumer<AuthInfo> success, Runnable failed) {
public AccountLoginWithPasswordDialog(Account oldAccount, Consumer<AuthInfo> success, Runnable failed) {
this.oldAccount = oldAccount;
this.success = success;
this.failed = failed;

View File

@@ -100,7 +100,17 @@ public class MicrosoftAccount extends Account {
@Override
public AuthInfo logInWithPassword(String password) throws AuthenticationException {
throw new UnsupportedOperationException();
MicrosoftSession acquiredSession = service.authenticate();
if (acquiredSession.getProfile() == null) {
session = service.refresh(acquiredSession);
} else {
session = acquiredSession;
}
authenticated = true;
invalidate();
return session.toAuthInfo();
}
@Override

View File

@@ -119,7 +119,12 @@ public class MicrosoftService {
pair("client_secret", callback.getClientSecret()),
pair("refresh_token", oldSession.getRefreshToken()),
pair("grant_type", "refresh_token"))
.accept("application/json").getJson(LiveRefreshResponse.class);
.accept("application/json")
.ignoreHttpErrorCode(400)
.ignoreHttpErrorCode(401)
.getJson(LiveRefreshResponse.class);
handleLiveErrorMessage(response);
return authenticateViaLiveAccessToken(response.accessToken, response.refreshToken);
} catch (IOException e) {
@@ -129,6 +134,22 @@ public class MicrosoftService {
}
}
private void handleLiveErrorMessage(LiveErrorResponse response) throws AuthenticationException {
if (response.error == null || response.errorDescription == null) {
return;
}
switch (response.error) {
case "invalid_grant":
if (response.errorDescription.contains("The user must sign in again and if needed grant the client application access to the requested scope")) {
throw new CredentialExpiredException();
}
break;
}
throw new RemoteAuthenticationException(response.error, response.errorDescription, "");
}
private String getUhs(XBoxLiveAuthenticationResponse response, String existingUhs) throws AuthenticationException {
if (response.errorCode != 0) {
throw new XboxAuthorizationException(response.errorCode, response.redirectUrl);
@@ -336,13 +357,24 @@ public class MicrosoftService {
public static class NoXuiException extends AuthenticationException {
}
public static class LiveErrorResponse {
@SerializedName("error")
public String error;
@SerializedName("error_description")
public String errorDescription;
@SerializedName("correlation_id")
public String correlationId;
}
/**
* Error response: {"error":"invalid_grant","error_description":"The provided
* value for the 'redirect_uri' is not valid. The value must exactly match the
* redirect URI used to obtain the authorization
* code.","correlation_id":"??????"}
*/
public static class LiveAuthorizationResponse {
public static class LiveAuthorizationResponse extends LiveErrorResponse {
@SerializedName("token_type")
public String tokenType;
@@ -365,7 +397,7 @@ public class MicrosoftService {
public String foci;
}
private static class LiveRefreshResponse {
private static class LiveRefreshResponse extends LiveErrorResponse {
@SerializedName("expires_in")
int expiresIn;