我正在尝试使用Oauth2对“我的动画列表”用户进行身份验证(如下所示)
guide
)用于我的Android应用程序。
第一步:
获取授权令牌
在这里,我使用WebView提示用户输入用户名和密码。就我所知,这一步似乎奏效了。
private static final String REDIRECT_URL = "http://localhost/oauth";
private static final String CLIENT_ID = "9c..."; // omitted
private static final String OAUTH_BASE_URL = "https://myanimelist.net/v1/oauth2/";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
/*
* Before you can authenticate a user, your client needs to generate a Code Verifier and a
* Code Challenge. A Code Verifier is a high-entropy, cryptographic, random string
* containing only the characters [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~".
* The length of the string must be between 43 and 128 characters.
*
* MAL only allows the plain transformation for the Code Challenge.
* In other words, it means that you have to set the Code Challenge equal to the
* Code Verifier.
*/
String codeChallenge = PKCEGenerator.generateVerifier(128);
webview = findViewById(R.id.login_webview);
webview.getSettings().setJavaScriptEnabled(true);
webview.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request){
Log.d(TAG, "Redirecting to: " + request.getUrl());
Uri url = request.getUrl();
if(url.toString().contains(REDIRECT_URL)){
String authorizationCode = url.getQueryParameter("code");
Log.d(TAG, "Received authorization code: " + authorizationCode);
webview.setVisibility(View.GONE);
getUserAccessToken(authorizationCode, codeChallenge);
}
return false;
}
});
authenticateMAL(codeChallenge);
}
private void authenticateMAL(String codeChallenge) {
Log.d(TAG, "Code challenge (" + codeChallenge.length() + "): " + codeChallenge);
String loginUrl = OAUTH_BASE_URL + "authorize" +
"?response_type=code" +
"&redirect_uri=" + REDIRECT_URL +
"&client_id=" + CLIENT_ID +
"&code_challenge=" + codeChallenge;
Log.d(TAG, "Login url: " + loginUrl);
webview.loadUrl(loginUrl);
}
据我所知,这很有效。我拿到了
authorizationCode
正如所料。
第二步:
获取用户访问令牌&刷新令牌
这里,我正在使用
Mal4J
对于下一个身份验证步骤:
private void getUserAccessToken(String authorizationCode, String codeChallenge) {
Single.fromCallable(() -> {
MyAnimeListAuthenticator authenticator = new MyAnimeListAuthenticator(
CLIENT_ID, null, authorizationCode, codeChallenge);
return authenticator.getAccessToken();
})
.subscribeOn(Schedulers.io())
.doOnError(throwable -> {
Log.e(TAG, "Error while retrieving token!", throwable);
})
.onErrorComplete()
.subscribe(token -> {
Log.d(TAG, "--> access token: " + token.getToken());
Log.d(TAG, "--> refresh token: " + token.getRefreshToken());
});
}
不幸的是,这会导致以下错误:
E/LoginActivity: Error while retrieving token!
com.kttdevelopment.mal4j.HttpException: Server returned code 400 from 'https://myanimelist.net/v1/oauth2/token':
at com.kttdevelopment.mal4j.MyAnimeListAuthenticator.parseToken(MyAnimeListAuthenticator.java:505)
at com.kttdevelopment.mal4j.MyAnimeListAuthenticator.<init>(MyAnimeListAuthenticator.java:139)
at florian.baierl.daily_anime_news.ui.LoginActivity.lambda$getUserAccessToken$0(LoginActivity.java:99)
at florian.baierl.daily_anime_news.ui.-$$Lambda$LoginActivity$-bBBIb9OKRzdaFNsFkQdJSeVW74.call(Unknown Source:4)
at io.reactivex.rxjava3.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:43)
at io.reactivex.rxjava3.core.Single.subscribe(Single.java:4813)
at io.reactivex.rxjava3.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
at io.reactivex.rxjava3.core.Scheduler$DisposeTask.run(Scheduler.java:614)
at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:65)
at io.reactivex.rxjava3.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:56)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
你知道为什么会这样吗?我是不是错过了Oauth2中一些Android特有的东西?就我所见,我正确地从步骤1中检索到了身份验证代码。在那之后,我的代码似乎非常直截了当,所以我看不出错误可能在哪里。任何提示都将不胜感激!
编辑:
这是请求的样子(来自android studio的概要视图):
以下是答复:
编辑2:
将代码质询/验证程序硬编码为128次“A”(
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
)也不会改变行为: