Keycloak用户存储SPI的实现

时间:2019-08-13 12:02:01

标签: java keycloak keycloak-services

我正在尝试实现自定义密钥克隆Authenticator SPI,以针对外部数据源进行身份验证。 Spring boot Rest Service也可用,我也可以使用它。

我要解决的用例是

  
    

向用户显示密钥斗篷登录屏幕。提交用户已针对外部数据源进行了验证。

         

从外部数据源检索一些属性,将其映射到keycloak的ID和访问令牌。

         

还设置了相同用户同时登录多次的用户限制条件。

         

我当时在想,可以通过检索keycloak数据源中可用的用户会话信息来解决。如果我使用外部数据源,keycloak仍会保留会话信息吗?

  

我遵循了官方指南(https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi_walkthrough)第8.3节,该节与我所需要的非常相似。

现在我按照第11(https://www.keycloak.org/docs/latest/server_development/index.html#_user-storage-spi)节的规定开始学习,似乎也很合适。

我所做的是从实现自定义身份验证器SPI开始的,认为这不是正确的方法,现在实现了UserStorageProvider。

/***
 * From UserLookupProvider
 */
public UserModel getUserById(String id, RealmModel realm) {
    System.out.println("ID: " + id + ":REALM:" + realm);
    StorageId storageId = new StorageId(id);
    /**
     * StorageId.getExternalId() method is invoked to obtain 
     * the username embeded in the id parameter
     */
    String username = storageId.getExternalId();
    System.out.println("Name:" + username);
    return getUserByUsername(username, realm);
}

/***
 * From UserLookupProvider
 * This method is invoked by the Keycloak login page when a user logs in
 */
public UserModel getUserByUsername(String username, RealmModel realm) {
    System.out.println("USERNAME: " + username + ":REALM:" + realm);
    UserModel userModel = loadedUsers.get(username);
    if (userModel == null) {
        String password = properties.getProperty(username);
        if (password != null) {
            userModel = createUserModel(realm, username);
            System.out.println("New UserModel:");
            System.out.println(userModel.toString());
            loadedUsers.put(username, userModel);
        }
    }
    return userModel;
}

protected UserModel createUserModel(RealmModel realm, String username) {
    return new AbstractUserAdapter(session, realm, model) {
        @Override
        public String getUsername() {
            return username;
        }
    };
}

遵循文档(https://www.keycloak.org/docs/latest/server_development/index.html#packaging-and-deployment-2

  

我们的提供程序实现的类文件应放在jar中。您还必须在META-INF / services / org.keycloak.storage.UserStorageProviderFactory文件中声明提供程序工厂类。

这里的问题是:我创建的jar在“ META-INF”文件夹中没有services目录,我需要手动创建并添加它吗?

  

org.keycloak.examples.federation.properties.FilePropertiesStorageFactory   一旦创建了jar,就可以使用常规的WildFly方式进行部署:将jar复制到deploy /目录或使用JBoss CLI。

使用maven创建jar之后,将jar复制到“ keycloak-6.0.1 \ standalone \ deployments”文件夹中。但我在“用户联合身份列表”中看不到我的提供者User Federation List

任何建议/帮助将不胜感激!

预先感谢您的建议。

3 个答案:

答案 0 :(得分:2)

  • 好吧,您澄清了,您需要一个User Store Provider API。很棒

  • 现在您的第二个“问题/挑战”:

从外部数据源检索一些属性,将其映射到keycloak的ID和访问令牌。需要检索用户的唯一ID并将其作为主题ID添加到jwt中。这就是ID,当此令牌传递给其他服务时,其他服务便可以用来检索ID。

为此,您可以做的最好的事情是:

  1. 将这些用户的唯一数据添加为用户属性(请在管理控制台上查看)

  2. 在Keycloak上创建一个“客户端作用域”,并为“用户属性”创建一个映射器 将您想要(从用户)添加到ID令牌和访问令牌的属性映射。您还需要将客户与刚刚创建的“客户范围”联系在一起。这听起来可能有点令人困惑,但是该视频非常棒,我相信可以帮助您:https://www.youtube.com/watch?v=ZxpY_zZ52kU(大约6:30左右,您将看到如何向令牌添加额外的用户信息)< / p>

也请检出此页面:https://jwt.io/(当您在其中粘贴编码的令牌时,您可以看到它们的内容),对于开发人员来说是个不错的工具。

在您提出解决方案时,我将为您提供独特的会话,或者将其发布为其他问题,因为这是一个不同的问题。

希望有帮助。

答案 1 :(得分:1)

万一有人遇到这样的问题:

由于META-INF / services文件夹,未显示UserStorage SPI。它在文档中提供,但不清楚

在src / main / resources中,创建文件夹结构META-INF / services

在META-INF / services目录中创建一个名为org.keycloak.storage.UserStorageProviderFactory的文件(整个东西是文件名)。它的内容是您的SPI的完全限定的类名: com.test.UserSpi

deploy jar

答案 2 :(得分:0)

我不确定您需要什么。让我们先区分身份验证SPI(联合身份检查)与用户提供者SPI(联合用户)。第一个(文档的第8节-更多地专注于针对外部服务(类似于Facebook或google)对用户进行身份验证)。联合用户存储更像是将您的awn用户放置在具有旧版“角色结构”的旧版系统中,并且您基本上是想通过viecloak(通过导入它们或通过某些API查询via)来管理它们。该文档的11)。因此,请确定您确实需要什么。

2,您提到以下内容:

>  User is presented keycloak login screen. Onsubmission User is
> validated against external Datasource.
> 
> Retrieve some attributes from external datasource, map it to
> keycloak's id and access token.
> 
> Also put in a condition of user restriction of same user logging in
> multiple times at the same time.
> 
> I was thinking, it could be solved by retrieving user session
> information that's available in the keycloak datasource. If i use
> external datasource, does keycloak still maintain session information?

您是什么意思: 从外部数据源中检索一些属性,将其映射到keycloak的ID和访问令牌。 ?通常,您只检索用户核心信息,还可能检索角色和其他自定义属性(而不是会话信息)。 Keycloak本身作为基于openIDConnect的授权服务器,将生成acces令牌,该令牌已包含有关谁可以访问哪些受保护资源的信息,因此您实际上不需要从其他任何地方导入任何会话,也不必担心所述令牌的生成

关于: 还设置了相同用户登录的用户限制条件   。 。当您第一次登录时,您的客户到底想达到什么目的(或避免?),在这段时间内,您的客户收到了有效期为X的有效期的Bearer令牌。无需再次登录自己,直到令牌过期或被窃取为止;再次由您的Auth服务器处理,而不是由您实施。您想要更具体的内容吗?

我当时在想,可以通过检索keycloak数据源中可用的用户会话信息来解决。如果我使用外部数据源,keycloak仍会保留会话信息吗? 听起来不对,您指的是什么会话数据?还是您需要访问?您的用户数据,范围,角色等可以通过KEycloak Rest API(https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_overview)访问。您的外部数据源用于与用户相关的核心数据(而不是外部会话),为什么您认为需要导入外部会话?