Java 中的 Firebase 电子邮件+密码身份验证

Firebase email+password authentication in Java

我正在尝试使用他们的 REST API 在 Java 中使用 Firebase 电子邮件和密码身份验证,因为他们的 Admin SDK 不提供登录等所需的方法,只有用户管理方法。

this answer 的帮助下,我设法将以下代码放在一起,这些代码适用于正确的凭据,但在尝试处理错误时,例如USER_NOT_FOUND 或 INVALID_PASSWORD,我得到的只是 java.io.IOException,其中包含详细信息 Server returned HTTP response code: 400 for URL: https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=key

package com.amansprojects.craftclaw;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class FirebaseAuthManager {

    private static final String BASE_URL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/";
    private static final String OPERATION_AUTH = "verifyPassword";
    private static final String OPERATION_ACCOUNT_INFO = "getAccountInfo";

    private String firebaseKey;

    private static FirebaseAuthManager instance = null;

    protected FirebaseAuthManager() {
        firebaseKey = "MY_KEY_HERE";
    }

    public static FirebaseAuthManager getInstance() {
        if (instance == null) {
            instance = new FirebaseAuthManager();
        }
        return instance;
    }

    public String auth(String username, String password) {
        HttpURLConnection urlRequest = null;
        String token = null;

        try {
            URL url = new URL(BASE_URL + OPERATION_AUTH + "?key=" + firebaseKey);
            urlRequest = (HttpURLConnection) url.openConnection();
            urlRequest.setDoOutput(true);
            urlRequest.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            OutputStream os = urlRequest.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
            osw.write("{\"email\": \"" + username + "\", \"password\": \"" + password + "\", \"returnSecureToken\": true}");
            osw.flush();
            osw.close();

            urlRequest.connect();

            JsonParser jp = new JsonParser();
            JsonElement root = jp.parse(new InputStreamReader((InputStream) urlRequest.getContent()));
            JsonObject rootObj = root.getAsJsonObject();

            token = rootObj.get("idToken").getAsString();
            System.out.println(rootObj); // debugging
        } catch (IOException e) { e.printStackTrace(); return null; }
        finally { urlRequest.disconnect(); }
        return token;
    }

    public String getAccountInfo(String token) {
        HttpURLConnection urlRequest = null;
        String email = null;

        try {
            URL url = new URL(BASE_URL + OPERATION_ACCOUNT_INFO + "?key=" + firebaseKey);
            urlRequest = (HttpURLConnection) url.openConnection();
            urlRequest.setDoOutput(true);
            urlRequest.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            OutputStream os = urlRequest.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
            osw.write("{\"idToken\": \"" + token + "\"}");
            osw.flush();
            osw.close();
            urlRequest.connect();

            JsonParser jp = new JsonParser();
            JsonElement root = jp.parse(new InputStreamReader((InputStream) urlRequest.getContent()));
            JsonObject rootObj = root.getAsJsonObject();

            email = rootObj.get("users").getAsJsonArray().get(0).getAsJsonObject().get("email").getAsString();
        } catch (IOException e) { e.printStackTrace(); return null; }
        finally { urlRequest.disconnect(); }
        return email;
    }
}

提前致谢。

编辑:我也尝试过 Firebase 在其文档页面上显示的其他 domain/endpoint 组合:https://identitytoolkit.googleapis.com/v1/accounts:endpoint

在调试另一个问题时,我发现 Apache http 库不会针对 400 错误代码抛出 IOException,而是让您继续解析 JSON。

这是我在 Java 中与 class 接口的最终 Firebase Auth REST API。

package com.amansprojects.craftclaw;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * A class to interface with the Firebase Auth REST API.
 */
public class FirebaseAuthManager {
    private static final String BASE_URL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/";
    private static final String OPERATION_AUTH = "verifyPassword";
    private static final String OPERATION_ACCOUNT_INFO = "getAccountInfo";
    private static final String OPERATION_SEND_PASSWORD_RESET = "getOobConfirmationCode";

    private final String firebaseKey;

    private static FirebaseAuthManager instance = null;

    protected FirebaseAuthManager() {
        firebaseKey = "YOUR_KEY_HERE";
    }

    public static FirebaseAuthManager getInstance() {
        if (instance == null) {
            instance = new FirebaseAuthManager();
        }
        return instance;
    }

    /**
     * Exchange an email and password with the Firebase Auth REST API for an ID token.
     * @param username A username or email registered with Firebase Authentication.
     * @param password The password associated with the username or email.
     * @return An ID token from Firebase.
     * @throws FirebaseAuthException
     */
    public String auth(String username, String password) throws FirebaseAuthException {
        String token;
        try {
            HttpClient httpclient = HttpClients.createDefault();
            HttpPost httppost = new HttpPost(BASE_URL + OPERATION_AUTH + "?key=" + firebaseKey);
            List<NameValuePair> params = new ArrayList<NameValuePair>(1);
            params.add(new BasicNameValuePair("email", username));
            params.add(new BasicNameValuePair("password", password));
            params.add(new BasicNameValuePair("returnSecureToken", "true"));
            httppost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
            HttpEntity entity = httpclient.execute(httppost).getEntity();

            JsonParser jp = new JsonParser();
            JsonElement root = jp.parse(new InputStreamReader(entity.getContent()));
            JsonObject rootObj = root.getAsJsonObject();

            if (rootObj.get("error") != null) {
                throw new FirebaseAuthException(rootObj.get("error").getAsJsonObject().get("message").getAsString());
            }
            token = rootObj.get("idToken").getAsString();
        } catch (IOException e) { System.out.println(e.getMessage()); return null; }
        return token;
    }

    /**
     * Exchange an ID token with the Firebase Auth REST API for a User object.
     * @param token An ID token from Firebase.
     * @return A user object with the email and UID returned by Firebase.
     */
    public User getAccountInfo(String token) {
        try {
            HttpClient httpclient = HttpClients.createDefault();
            HttpPost httppost = new HttpPost(BASE_URL + OPERATION_ACCOUNT_INFO + "?key=" + firebaseKey);
            List<NameValuePair> params = new ArrayList<NameValuePair>(1);
            params.add(new BasicNameValuePair("idToken", token));
            httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            HttpEntity entity = httpclient.execute(httppost).getEntity();

            JsonParser jp = new JsonParser();
            JsonElement root = jp.parse(new InputStreamReader(entity.getContent()));
            JsonObject rootObj = root.getAsJsonObject();

            JsonObject userObj = rootObj.get("users").getAsJsonArray().get(0).getAsJsonObject();
            return new User(userObj.get("email").getAsString(), userObj.get("localId").getAsString(), token);
        } catch (IOException e) { System.out.println(e.getMessage()); return null; }
    }

    /**
     * Send a reset password email via Firebase.
     * @param email The email address to send the reset password email to.
     */
    public void sendResetPasswordLink(String email) {
        try {
            HttpClient httpclient = HttpClients.createDefault();
            HttpPost httppost = new HttpPost(BASE_URL + OPERATION_SEND_PASSWORD_RESET + "?key=" + firebaseKey);
            List<NameValuePair> params = new ArrayList<NameValuePair>(2);
            params.add(new BasicNameValuePair("requestType", "PASSWORD_RESET"));
            params.add(new BasicNameValuePair("email", email));
            httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            httpclient.execute(httppost);
        } catch (IOException e) { e.printStackTrace(); }
    }

    /**
     * Exchange a refresh token with the Firebase Auth REST API for a new ID token.
     * @param refreshToken The refresh token used to receive an ID token.
     * @return A new ID token from Firebase.
     */
    public String[] exchangeRefreshToken(String refreshToken) {
        try {
            HttpClient httpclient = HttpClients.createDefault();
            HttpPost httppost = new HttpPost("https://securetoken.googleapis.com/v1/token?key="+ firebaseKey);
            List<NameValuePair> params = new ArrayList<NameValuePair>(2);
            params.add(new BasicNameValuePair("grant_type", "refresh_token"));
            params.add(new BasicNameValuePair("refresh_token", refreshToken));
            httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
            HttpEntity entity = httpclient.execute(httppost).getEntity();
            if (entity != null) {
                JsonParser jp = new JsonParser();
                JsonElement root = jp.parse(new InputStreamReader(entity.getContent()));
                JsonObject rootObj = root.getAsJsonObject();
                return new String[]{ rootObj.get("id_token").getAsString(), rootObj.get("refresh_token").getAsString() };
            }
        } catch (IOException e) { e.printStackTrace(); }
        return null;
    }
}