无法在Servlet之外检索Google凭据

时间:2013-12-04 19:16:19

标签: google-glass google-mirror-api

我们希望推动定期或事件驱动的Glass Timeline更新,我们遇到了Java Glass入门项目中提供的AuthUtil问题。

通常情况下,我们只需在用户启用具有Google权限的应用后调用以下内容:

Credential credential = AuthUtil.getCredential(googleUserToken);

在身份验证servlet或通知servlet期间从HttpRequest检索Google UserToken时,这非常有效。

我们在App身份验证阶段坚持用户的Google用户令牌。但是,尝试从Quartz作业或消息队列中获取Google凭据时,相同的有效Google UserTokens会返回null Credential对象。

我们调试了代码并注意到AuthUtil正在使用ListableMemoryCredentialStore,并且当尝试从Quartz作业中检索Credential时,此存储为空。

1 个答案:

答案 0 :(得分:2)

在这里回答我自己的问题。与starter项目一起打包的AuthUtil帮助程序仅提供Google Credentials的内存缓存。如果服务器重新启动或新实例,缓存将消失,然后用户将被定向到Google OAuth流程。

要防止这种情况并为Glass应用程序提供可伸缩性,请使用以下CredentialStore实现并替换AuthUtil中ListableMemoryCredentialStore的使用。它不是最干净的,但它是轻量级的并且保留了AuthUtil的单一意图。

将JDBC路径替换为每个数据库帮助程序方法的数据库,模式,用户名和密码。 Google凭证表只不过是一个存储userId作为PK,accessToken,resfreshToken和expriationTimeInMillis的四列表。显然,您可以根据需要随意调整数据模型。

/**
 * Created by Dayel Ostraco
 * Date: 12/4/13
 *
 * This extends the Google OAuth2 CredentialStore interface and uses a Database backend to     persist Google Credentials
 * in a thread safe manner.
 *
 */
public class DatabaseCredentialStore implements CredentialStore {

private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseCredentialStore.class);

/**
 * Lock on access to the database Credential store.
 */
private final Lock lock = new ReentrantLock();

/**
 * Stores a Google OAuth2 Credential in the database.
 *
 * @param userId String
 * @param credential Google OAuth2 Credential
 */
public void store(String userId, Credential credential) {
    lock.lock();
    try {
        DatabasePersistedCredential item = findByUserId(userId);
        if (item == null) {
            item = new DatabasePersistedCredential();
            item.store(userId, credential);
            create(item);
        }
        item.store(userId, credential);
    } finally {
        lock.unlock();
    }
}

/**
 * Removes a persisted Google Credential from the database.
 *
 * @param userId String
 * @param credential Google OAuth2 Credential
 */
public void delete(String userId, Credential credential) {
    lock.lock();
    try {
        DatabasePersistedCredential item = findByUserId(credential.getAccessToken());
        delete(item);
    } finally {
        lock.unlock();
    }
}

/**
 * Loads a Google Credential with the contents of the persisted Google Credentials.
 *
 * @param userId String
 * @param credential Google OAuth2 Credential
 * @return boolean
 */
public boolean load(String userId, Credential credential) {
    lock.lock();
    try {
        DatabasePersistedCredential item = findByUserId(userId);
        if (item != null) {
            item.load(userId, credential);
        }
        return item != null;
    } finally {
        lock.unlock();
    }
}

/**
 * Returns all users in the Google Credentials Table
 * @return List of all persisted Google authenticated user IDs
 */
public List<String> listAllUsers() {

    List<String> userIds = new ArrayList<>();

    for(DatabasePersistedCredential credential : findAll()) {
        userIds.add(credential.getUserId());
    }

    return userIds;
}

/****************
 * JDBC Methods *
 ***************/

/**
 * Persists a new Google Credential to the database.
 *
 * @param credential DatabasePersistedCredential
 */
private void create(DatabasePersistedCredential credential) {

    Connection connect;
    PreparedStatement preparedStatement;

    try {
        Class.forName("com.mysql.jdbc.Driver");
        connect = DriverManager.getConnection("jdbc:mysql://yourdatabaseurl:3306/schema?user=un&password=password");

        preparedStatement = connect.prepareStatement("INSERT INTO GoogleCredential values (?, ?, ?, ?)");
        preparedStatement.setString(1, credential.getUserId());
        preparedStatement.setString(2, credential.getAccessToken());
        preparedStatement.setString(3, credential.getRefreshToken());
        preparedStatement.setLong(4, credential.getExpirationTimeInMillis());
        preparedStatement.executeUpdate();

    } catch (ClassNotFoundException e) {
        LOGGER.error("Could not load MySQL Driver.", e);
    } catch (SQLException e) {
        LOGGER.error("Could not persist DatabasePersistedCredential.", e);
    }
}

/**
 * Removes a Google credential from the database.
 *
 * @param credential DatabasePersistedCredential
 */
private void delete(DatabasePersistedCredential credential) {

    Connection connect;
    PreparedStatement preparedStatement;
    ResultSet resultSet;

    try {
        Class.forName("com.mysql.jdbc.Driver");
        connect = DriverManager.getConnection("jdbc:mysql://yourdatabaseurl:3306/schema?user=un&password=password");

        preparedStatement = connect.prepareStatement("DELETE * FROM spgglassdb.GoogleCredential WHERE userId = ?;");
        preparedStatement.setString(1, credential.getUserId());
        preparedStatement.executeQuery();

    } catch (ClassNotFoundException e) {
        LOGGER.error("Could not load MySQL Driver.", e);
    } catch (SQLException e) {
        LOGGER.error("Could not persist DatabasePersistedCredential.", e);
    }
}

/**
 * Returns the Google credentials for a user with the passed in userId.
 *
 * @param userId String
 * @return DatabasePersistedCredential
 */
private DatabasePersistedCredential findByUserId(String userId) {

    Connection connect;
    PreparedStatement preparedStatement;
    ResultSet resultSet;

    try {
        Class.forName("com.mysql.jdbc.Driver");
        connect = DriverManager.getConnection("jjdbc:mysql://yourdatabaseurl:3306/schema?user=un&password=password");

        preparedStatement = connect.prepareStatement("SELECT * FROM spgglassdb.GoogleCredential WHERE userId = ?;");
        preparedStatement.setString(1, userId);
        resultSet = preparedStatement.executeQuery();

        List<DatabasePersistedCredential> credentials = convertResultsSet(resultSet);
        if(credentials.size()==1) {
            return credentials.get(0);
        } else {
            return null;
        }

    } catch (ClassNotFoundException e) {
        LOGGER.error("Could not load MySQL Driver.", e);
    } catch (SQLException e) {
        LOGGER.error("Could not persist DatabasePersistedCredential.", e);
    }

    return null;
}

/**
 * Returns all DatabasePersistedCredentials located in the database.
 *
 * @return List<DatabasePersistedCredential>
 */
private List<DatabasePersistedCredential> findAll() {

    Connection connect;
    PreparedStatement preparedStatement;
    ResultSet resultSet;

    try {
        Class.forName("com.mysql.jdbc.Driver");
        connect = DriverManager.getConnection("jdbc:mysql://yourdatabaseurl:3306/schema?user=un&password=password");

        preparedStatement = connect.prepareStatement("SELECT * FROM spgglassdb.GoogleCredential;");
        resultSet = preparedStatement.executeQuery();

        List<DatabasePersistedCredential> credentials = convertResultsSet(resultSet);
        return credentials;

    } catch (ClassNotFoundException e) {
        LOGGER.error("Could not load MySQL Driver.", e);
    } catch (SQLException e) {
        LOGGER.error("Could not persist DatabasePersistedCredential.", e);
    }

    return null;
}

/**
 * Converts a ResultSet to a collection of DatabasePersistedCredentials.
 *
 * @param resultSet JDBC ResultSet
 * @return List<DatabasePersistedCredential>
 * @throws SQLException
 */
private List<DatabasePersistedCredential> convertResultsSet(ResultSet resultSet) throws SQLException {

    List<DatabasePersistedCredential> credentials = new ArrayList<>();

    while (resultSet.next()) {
        DatabasePersistedCredential credential = new DatabasePersistedCredential();
        String accessToken = resultSet.getString("accessToken");
        String refreshToken = resultSet.getString("refreshToken");
        Long expirationTimeInMillis = resultSet.getLong("expirationTimeInMillis");

        credential.setAccessToken(accessToken);
        credential.setRefreshToken(refreshToken);
        credential.setExpirationTimeInMillis(expirationTimeInMillis);

        credentials.add(credential);
    }

    return credentials;
}
}