访问 Keycloak 返回的用户 Oauth 令牌

Accessing user Oauth tokens returned by Keycloak

我有一个 Keycloak(独立版)v1.9。4.Final 在 AWS 实例上使用 Wildfly 10 安装设置并尝试使用 keycloak(通过 keycloak 的登录页面)和 Twitter4j 通过 Twitter 对用户进行身份验证然后显然让我的应用程序进行身份验证并查看用户时间线等。

我已经配置了身份提供者 (Twitter)、领域和我的客户端应用程序。

我还在 apps.twitter.com 上设置了一个 Twitter 应用程序,并将密钥放入我的 twitter4j.properties 文件中。

到目前为止,我能够:

  1. 转到我的应用程序的 JSF 网页并重定向到 Keycloak 的 /auth 登录页面
  2. 单击 Twitter 徽标并使用我的 Twitter 帐户登录(与拥有 Twitter 应用程序的帐户分开的帐户)
  3. 完成Keycloak要求的用户信息
  4. 完成用户信息后,Keycloak 成功将用户引导回客户端应用程序(在本例中为 JSF 页面)。

问题是,我无法弄清楚如何获取用户 OAuth AccessToken 和 AccessTokenSecret 的访问权限以与 Twitter 应用程序的 ConsumerKey 和 ConsumerKeySecret 结合使用。

下面是相关的代码片段:

twitterLogin.xhtml

...
#{twitterBean.getUserInfo()}
...


TwitterBean.java

@Context
private final FacesContext facesContext = FacesContext.getCurrentInstance();
private final Twitter twitter = TwitterFactory.getSingleton();

public String getUserInfo() {

    if (facesContext != null) {
        HttpSession httpSession = (HttpSession) facesContext.getExternalContext().getSession(false);
        KeycloakSecurityContext keycloakContext = (RefreshableKeycloakSecurityContext) httpSession.getAttribute(KeycloakSecurityContext.class.getName());
        queryTwitter(keycloakContext.getTokenString(), keycloakContext.getIdTokenString());
    }
}

public void queryTwitter(String accessToken, String accessTokenSecret) {
    ConfigurationBuilder cb = new ConfigurationBuilder();
    cb.setDebugEnabled(true)
            .setOAuthConsumerKey("APPLICATIONS_CONSUMER_KEY")
            .setOAuthConsumerSecret("APPLICATIONS_CONSUMER_KEY_SECRET")
            .setOAuthAccessToken(accessToken)
            .setOAuthAccessTokenSecret(accessTokenSecret);
    TwitterFactory tf = new TwitterFactory(cb.build());
    twitter = tf.getInstance();
    user = twitter.verifyCredentials();
    ...
}

根据我们如何安排各种令牌(在不同的地方尝试不同的令牌字符串),我们在调用 verifyCredentials() 时收到 Twitter 返回的不同错误,但本质上都是 "invalid authentication".

我们很明显 .getTokenString() 和 .getIdTokenString() 方法不是正确的使用方法,但我们不知道 Keycloak 将在哪里提供用户的 oauth 令牌。

我们尝试查看 facesContext.getExternalContext().getRequest() 和 facesContext.getExternalContext().getResponse(),但运气不佳。

我的问题是,当用户通过 Twitter 进行身份验证并在 Keycloak 中注册用户后,Keycloak 重定向回客户端应用程序(服务提供商)时,oauth 令牌保存在哪里,以便我们可以访问它们,然后双重验证(Application/User 验证)?

希望此代码片段对某人有所帮助...

@PostConstruct
public void init() {
    facesContext = FacesContext.getCurrentInstance();
}


public void login() {

    if (user == null) {

        if (facesContext != null) {
            HttpSession httpSession = (HttpSession) facesContext.getExternalContext().getSession(false);
            KeycloakSecurityContext keycloakContext = (RefreshableKeycloakSecurityContext) httpSession.getAttribute(KeycloakSecurityContext.class.getName());
            MyAccessToken accessToken = generateMyAccessToken(keycloakContext);

        }
    }
}

private MyAccessToken generateMyAccessToken(KeycloakSecurityContext keycloakContext) {
    AccessToken keycloakToken = keycloakContext.getToken();
    MyAccessToken token = new MyAccessToken();

    token.withEmail(keycloakToken.getEmail())
            .withExpiration(keycloakToken.getExpiration())
            .withUsername(keycloakToken.getPreferredUsername())
            .withOauthToken(getTwitterOAuthResponse(keycloakContext.getTokenString()))
            .withFirstName(keycloakToken.getGivenName())
            .withLastName(keycloakToken.getFamilyName());

    return token;
}

private OAuthTokenWrapper getTwitterOAuthResponse(final String tokenString) {
    ClientRequestFilter authFilter = new ClientRequestFilter() {
        @Override
        public void filter(ClientRequestContext requestContext) throws IOException {
            requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + tokenString);
        }
    };

    Client client = ClientBuilder.newBuilder().register(authFilter).build();
    WebTarget target = client.target(getIdentityProviderTokenUrl());

    TwitterOAuthResponse resp = target.request().get().readEntity(TwitterOAuthResponse.class);
    return new OAuthTokenWrapper(resp.getToken(), resp.getTokenSecret());
}

private String getIdentityProviderTokenUrl() {
    return "https://login.example.com:8443/auth/realms/myapp/broker/twitter/token";

}