简体   繁体   English

Keycloak用户存储SPI身份验证流程

[英]Keycloak User Storage SPI Authentication Flow

From a frontend application on signIn, user is redirected to Keycloak page. 从登录时的前端应用程序,将用户重定向到Keycloak页面。 user is authenticated against an external service 用户已通过外部服务认证

I have implemented keycloak User Storage SPI flow. 我已经实现了keycloak用户存储SPI流。 It authenticates against an external source. 它根据外部来源进行身份验证。 Keycloak is updated with external storage attributes, it's working if it's updated in getUserByUsername method. Keycloak已使用外部存储属性进行了更新,如果在getUserByUsername方法中进行了更新,则它可以正常工作。

I am validating the userValidation in isValid method and updating the userAttributes in UserModel and LocalHashMap. 我正在验证isValid方法中的userValidation并更新UserModel和LocalHashMap中的userAttributes。

From the logs, I see UserStoreProviderFactory creates two instances to authenticate one transaction/login 从日志中,我看到UserStoreProviderFactory创建两个实例来验证一个交易/登录

My question is, does Keycloak creates two instances of UserStorageProvider for one single authentication flow. 我的问题是,是否Keycloak创建一个单一的认证流程UserStorageProvider的两个实例。 Since it's calling multiple times, UserModel created on isValid method has to be cached and retrieved it again on the second time, can it be avoided? 由于它多次调用,因此必须缓存在isValid方法上创建的UserModel并在第二次再次检索它,是否可以避免?

Why does it call getUserByUserName() method multiple times on the first userStorageProvider call 为什么在第一次userStorageProvider调用中多次调用getUserByUserName()方法

            UserStorageProviderFactory
                 -> Creates instance of UserStorageProvider
                    -> UserStorage provider calls getUserById method
                    -> UserStorage provider calls getUserByUserName method
                    -> UserStorage provider calls isValid method
                                 on true, keycloak 
            UserStorageProviderFactory
                 -> Creates instance of UserStorageProvider
                    -> UserStorage provider calls getUserById method
                    -> UserStorage provider calls getUserByUserName method
                           returns UserModel


 @Override
public UserModel getUserById(String id, RealmModel realm) {
    logger.debug("__ ########## getUserById  ID:" + "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
 */
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
    logger.debug("__ %%%%%%%%%% getUserByUsername ID:" + username + ":REALM:" + realm);
    logger.debug("Provider Num:" + this.randomNum);
    UserModel userModel = loadedUsers.get(username);

    UserModel local = session.userLocalStorage().getUserByUsername(username, realm);
    logger.debug("*#@#$ local session:" + local);

    if (userModel == null) {
        logger.debug("In NULLLLLLLLLLLLLLLLLLL ");
        userModel = createUserModel(realm, username);
        // set for demo...
        userModel.setSingleAttribute("externalId", Integer.toString(10));
    } else {
        logger.debug("__ ELSEEEEEEEEEEEEEE getUserByUsername sku:" +  userModel.getFirstAttribute("sku"));
        userModel.setSingleAttribute("externalId", Integer.toString(12));
    }

    return userModel;
}

public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
    logger.debug("__ , 1111111111 isValid:input type:" +  input.getType() + ":userName:" + user.getUsername());

    UserCredentialModel cred = (UserCredentialModel)input;

    if (!supportsCredentialType(input.getType()) 
            || !(input instanceof UserCredentialModel)) {
        logger.warn("__, credentialType: " + input.getType() + ": NOT supported");
        return false;
    }

    UserDTO model = new UserDTO();
    model.setEmailId(user.getUsername());
    model.setPassword(cred.getValue());

    try {
        ResteasyClient client = new ResteasyClientBuilder().build();
        ResteasyWebTarget target = client.target(properties.getProperty("userUrl"));
        Response response = target.request().post(
                Entity.entity(model, "application/json"));

        ResponseDTO<UserResponseDTO> responseDto = response.readEntity(new GenericType<ResponseDTO<UserResponseDTO>>() {});
        logger.debug("__ , !!!!!!!!!!! json response:" +  responseDto);
        logger.debug("!!!! Provider Num:" + this.randomNum);
        if (responseDto.getCode() == 200) {
            UserResponseDTO userResponseDto = responseDto.getData();
            UserDetailsDTO userDetailsDto = userResponseDto.getDetails();
            user.setEmail(userDetailsDto.getEmailId());
            user.setFirstName(userDetailsDto.getFirstName());

            logger.debug("!!!!@@@@@@@@ Provider Num:" + this.randomNum);
            logger.debug("__ , returning success from isValid:" + user.getUsername() +":::"); 
            loadedUsers.put(user.getUsername(), user);
            return true;
        }
        response.close();

    } catch(Exception ex) {
        logger.error("Exception Occured accessing:", ex);
    }

    return false;

}

Logs(to show how many times getUserById() and getUserByUserName() method is called, UserStorageFactory instantiates twice UserStorageProvider Instances) 日志(以显示调用getUserById()和getUserByUserName()方法的次数,UserStorageFactory实例化两次UserStorageProvider实例)

2019-08-30 08:49:26,273 DEBUG [org.test.keycloak.userstore.factory.TestUserStoreProviderFactory] (default task-2) userURL: http://localhost:8280/login 2019年8月30日08:49:26273 DEBUG [org.test.keycloak.userstore.factory.TestUserStoreProviderFactory](默认任务-2)userURL: HTTP://本地主机:8280 /登录

2019-08-30 08:49:26,283 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,291 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,319 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) In NULLLLLLLLLLLLLLLLLLL 2019-08-30 08:49:26,951 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ , !!!!!!!!!!! 2019-08-30 08:49:26,283调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########## getUserById ID:ID:f:4a65ac95-6b5d- 4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,291调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,319 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务-2)在2019年8月30日NULLLLLLLLLLLLLLLLLLL 08:49:26951 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务-2)__, !!!!!!!!!!! json response:Message:Logged in :status:Success 2019-08-30 08:49:26,952 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,953 INFO [stdout] (default task-2) Name:test@gmail.com json响应:消息:已登录:状态:成功2019-08-30 08:49:26,952调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ######### getUserById ID:ID:f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,953信息[标准输出](默认任务2),名称:test@gmail.com

2019-08-30 08:49:26,960 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,962 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) LOADEDUSERS, keysize:0 2019-08-30 08:49:26,962 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) In NULLLLLLLLLLLLLLLLLLL 2019-08-30 08:49:26,965 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ , returning success from isValid:test@gmail.com::: 2019-08-30 08:49:26,960调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM: org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,962调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)LOADEDUSERS,密钥大小:0 2019-08- 30 08:49:26962 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务-2)在2019年8月30日NULLLLLLLLLLLLLLLLLLL 08:49:26965 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认task-2)__,从isValid:test@gmail.com :::返回成功

2019-08-30 08:49:26,966 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,986 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,022 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ELSEEEEEEEEEEEEEE getUserByUsername sku:1 2019-08-30 08:49:26,966调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########## getUserById ID:ID:f:4a65ac95-6b5d- 4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:26,986调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,022调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ELSEEEEEEEEEEEEEE getUserByUsername sku:1

2019-08-30 08:49:27,056 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) LOADEDUSERS, keysize:1 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ELSEEEEEEEEEEEEEE getUserByUsername sku:1 2019-08-30 08:49:27,061 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,056调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########## getUserById ID:ID:f:4a65ac95-6b5d- 4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)LOADEDUSERS,密钥大小:1 2019-08-30 08:49:27,059 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2 )__ ELSEEEEEEEEEEEEEEEE getUserByUsername sku:1 2019-08-30 08:49:27,061 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%%% getUserByUsername ID:test @ gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a

2019-08-30 08:49:27,071 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,073 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,073 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ELSEEEEEEEEEEEEEE getUserByUsername sku:1 2019-08-30 08:49:27,071调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########## getUserById ID:ID:f:4a65ac95-6b5d- 4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,073 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:27,073调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ELSEEEEEEEEEEEEEE getUserByUsername sku:1

2019-08-30 08:49:29,421 DEBUG [org.test.keycloak.userstore.factory.TestUserStoreProviderFactory] (default task-2) userURL: http://localhost:8280/login 2019-08-30 08:49:29,422 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:29,432 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:29,432 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) In NULLLLLLLLLLLLLLLLLLL 2019-08-30 08:49:29,581 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ ########## getUserById ID:ID: f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-3 2019-08-30 08:49:29,421调试[org.test.keycloak.userstore.factory.TestUserStoreProviderFactory](默认任务2)userURL: http:// localhost:8280 / login 2019-08-30 08:49: 29,422 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########### getUserById ID:ID:f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test @ gmail .com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:29,432调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%% %%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-30 08:49:29,432 DEBUG [org.test.keycloak.userstore .TestUserStoreProvider](默认任务2)在NULLLLLLLLLLLLLLLLLLLLL中2019-08-30 08:49:29,581 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ ########## getUserById ID:ID:f:4a65ac95-6b5d-4508-b7ec-348ae1da619d:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 2019-08-3 0 08:49:29,581 DEBUG [org.test.keycloak.userstore.TestUserStoreProvider] (default task-2) __ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak.models.cache.infinispan.RealmAdapter@64ddda7a 0 08:49:29,581调试[org.test.keycloak.userstore.TestUserStoreProvider](默认任务2)__ %%%%%%%%%% getUserByUsername ID:test@gmail.com:REALM:org.keycloak。 models.cache.infinispan.RealmAdapter@64ddda7a

Any suggestion/tips that you could make to help me solve/understand the workflow would be greatly appreciated! 您可以提出任何有助于我解决/理解工作流程的建议/技巧,将不胜感激!

As per docs, its state 根据文档,其状态

UserProvider - Remember that provider class instances are created once per transaction and are closed after the transaction completes. UserProvider-请记住,提供程序类实例每个事务创建一次,并在事务完成后关闭。

But in the application its called multiple times, because 但是在应用程序中它多次调用,因为

To store UserModel with custom attributes, 要存储具有自定义属性的UserModel,

this.session.userLocalStorage().addUser(realm, user.getUsername());

    @Override
public UserModel addUser(RealmModel realm, String username) {
    // userModel returned should be subclassed or instance of AbstractUserAdapterFederatedStorage
    return this.myUserModel;

}

To update the UserModel stored in localStorage, existing user should be removed and added. 要更新存储在localStorage中的UserModel,应删除并添加现有用户。

To remove an user FederationLink MUST be set. 要删除用户,必须设置FederationLink。

//ComponentModel ID of the provider. This sets a link between the provider and the imported user
user.setFederationLink(this.model.getId());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM