Keycloak自定义用户存储未显示属性。

huangapple go评论65阅读模式
英文:

Keycloak custom user storage not displaying attributes

问题

我已经在Keycloak中实现了一个自定义的用户存储SPI,用于与MySQL数据库进行通信。它完全按照正确的方式工作,除了一个特定的问题。

当我进入管理控制台的用户页面并点击查看所有用户时,检索到的用户都会正确显示所有字段(用户名、电子邮件、姓氏、名字)。

而当我点击打开的页面上的单个用户时,除了用户ID和用户名之外,所有字段都为空。

我不明白为什么在“查看所有”页面上这些数据会正确显示,而在“单个用户页面”上不会。我认为这是因为Keycloak试图从自己的存储中读取数据,因为:

  • 如果我在“单个用户页面”中设置自定义值并保存,然后在“查看所有页面”中,电子邮件字段将具有图像中的值(m.c...@hotmail.it),
  • 而在“单个用户页面”中它具有另一个值(我保存的自定义值)。

我使用了这个存储:https://github.com/Linch1/mysql-keycloak-storage-spi,由我编写(主要登录位于jar-module文件夹中)。我认为导致这种行为的主要原因是UserAdapter.java文件,在我的文件中,我写了以下内容:

// 代码部分不翻译

我阅读了文档并进行了一些搜索,但没有找到有用的信息。有任何想法吗?

英文:

I have implemented a custom user storage spi in keycloak for comunicating with a mysql db. It works all in the correct way except for a prticular.

When I go to the users page in the admin console and I click view all users the retrived users are correctly displayed with all the fields ( username, email, lastname, firstname )

Keycloak自定义用户存储未显示属性。

From the upper image the firt two users were created directly from keycloak, the last two were retrived from the mysql db.

instead when i click on the single user in the opened page all the fields except for the user id and the username are empty.

Keycloak自定义用户存储未显示属性。

I don't understand why in the view all page this datas are displayed correctly and in the single user page not. I suppose that is because kecloak tries to read the datas from it's own storage because

  • if i set this for ex the email field in the single user page with custom value and save it
  • happens that in the view all page the email has the value in the image (m.c...@hotmail.it )
  • and in the single user page it has another value ( the custom one that i saved ).

As storage is use this one https://github.com/Linch1/mysql-keycloak-storage-spi wrote by me ( the main login is in the jar-module folder). I think that the protagonist of this behaviour is the UserAdapter.java file, in mine i wrote this:

package mysql.storage.main;

import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;

import lombok.extern.jbosslog.JBossLog;
import mysql.storage.entity.User;

@JBossLog
public class UserAdapter extends AbstractUserAdapterFederatedStorage {

  private final User user;
  private final String keycloakId;
  

  
  public UserAdapter(KeycloakSession session, RealmModel realm, ComponentModel model, User user) {
    super(session, realm, model);
    this.user = user;
    this.EMAIL_ATTRIBUTE = user.getEmail();
    this.keycloakId = StorageId.keycloakId(model, String.valueOf(user.getId()) ); 
  }

  @Override
  public String getId() {
    return keycloakId;
  }

  @Override
  public String getUsername() {
	  log.infov("\n UserAdapter > getting username: " + user.getNickName() );
    return user.getNickName();
  }

  @Override
  public void setUsername(String username) {
    user.setNickName(username);
  }

  @Override
  public String getEmail() {
	  log.infov("\n UserAdapter > getting email: " + user.getEmail() );
    return user.getEmail();
  }

  @Override
  public void setEmail(String email) {
    user.setEmail(email);
  }

  @Override
  public String getFirstName() {
    return user.getFirstName();
  }

  @Override
  public void setFirstName(String firstName) {
    user.setFirstName(firstName);
  }

  @Override
  public String getLastName() {
    return user.getLastName();
  }

  @Override
  public void setLastName(String lastName) {
    user.setLastName(lastName);
  }
}

I read the doc and searched a while but found nothing usefull. Any ideas?

答案1

得分: 4

我认为这可能与您的提供商的用户查找优先级和缓存有关。

尝试编辑您的提供商配置(管理控制台 > 用户联合 > 您的提供商)的优先级值低于0(注意其他提供商的配置和优先级),以便它首先在您的自定义提供商中查找。

另外,您可能还想检查缓存策略值,尝试将其设置为NO_CACHE或为MAX_LIFESPAN组合框设置一个值。

英文:

I think it might be related to your provider's user lookup priority and cache.

Try and edit your provider's configuration (admin console > user federation > your provider) priority to a value lower than 0 (mind other providers config and priority), so that it looks it up first in your custom provider.

Also you might want to check the cache policy value, try to set it to NO_CACHE or set a value for the MAX_LIFESPAN combo box.

答案2

得分: 2

你需要在你的UserAdapter中重写getAttributes()方法:

@Override
public Map<String, List<String>> getAttributes() {
    MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
    attributes.add(UserModel.USERNAME, getUsername());
    attributes.add(UserModel.EMAIL, getEmail());
    attributes.add(UserModel.FIRST_NAME, getFirstName());
    attributes.add(UserModel.LAST_NAME, getLastName());
    return attributes;
}
英文:

You need to override getAttributes() in your UserAdapter:

@Override
public Map&lt;String, List&lt;String&gt;&gt; getAttributes() {
MultivaluedHashMap&lt;String, String&gt; attributes = new MultivaluedHashMap&lt;&gt;();
attributes.add(UserModel.USERNAME, getUsername());
attributes.add(UserModel.EMAIL,getEmail());
attributes.add(UserModel.FIRST_NAME,getFirstName());
attributes.add(UserModel.LAST_NAME,getLastName());
return attributes;
}

答案3

得分: 0

我通过使用Keycloak客户端更新用户值来解决了这个问题。我同时调用了这个方法,而用户正在保存到数据库,这样Keycloak也会在其数据库中具有这些值。

import java.util.List;
import java.util.stream.Collectors;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.UserRepresentation;

public class KeycloakRepo {
	
	private String SERVER_URL = "http://localhost:8180/auth";
	private String REALM = "master";
	private String REALM_USE = "myRealm";
	private String USERNAME = "admin_name";
	private String PASSWORD = "admin_pwd";
	private String CLIENT_ID = "admin-cli";
	private String CLIENT_SECRET = "73920be5-388b-48d9-bbfc-eb1786f5fcb0";
	
	private Keycloak keycloak = Keycloak.getInstance(
			SERVER_URL,
			REALM,
			USERNAME,
			PASSWORD,
			CLIENT_ID
			);
	
	
	public void KeycloakRepo() {}
	
	public void updateUser(String emailSearch, String email, String firstName, String lastName) {
		
		RealmResource realmResource = keycloak.realm(REALM_USE);
        UsersResource usersResource = realmResource.users();

    	List<UserRepresentation> users = usersResource.list().stream()
  	   		  .filter(user -> user.getUsername().contains(emailSearch))
  	   		  .collect(Collectors.toList());
    	UserRepresentation user_ = users.get(0);
        
        UserResource userResource = usersResource.get(user_.getId());
        UserRepresentation consumerUser = userResource.toRepresentation();
        
        consumerUser.setEmail(email);
        consumerUser.setFirstName(firstName);
        consumerUser.setLastName(lastName);
        
        userResource.update(consumerUser);
    	
    	System.out.println("found:" + users.size() + " " + user_.getId() + " " + user_.getFirstName() + " " + user_.getEmail());

	}
}
英文:

I solved this by updating the user values with the keycloak client. I called this method meanwhile that the user was being saved to the db so that also keycloak has this values inside of it's db.

import java.util.List;
import java.util.stream.Collectors;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.UserRepresentation;
public class KeycloakRepo {
private String SERVER_URL = &quot;http://localhost:8180/auth&quot;;
private String REALM = &quot;master&quot;;
private String REALM_USE = &quot;myRelam&quot;;
private String USERNAME = &quot;admin_name&quot;;
private String PASSWORD = &quot;admin_pwd&quot;;
private String CLIENT_ID = &quot;admin-cli&quot;;
private String CLIENT_SECRET = &quot;73920be5-388b-48d9-bbfc-eb1786f5fcb0&quot;;
private Keycloak keycloak = Keycloak.getInstance(
SERVER_URL,
REALM,
USERNAME,
PASSWORD,
CLIENT_ID
);
public void KeycloakRepo() {}
public void updateUser(String emailSearch, String email, String firstName, String Lastname) {
RealmResource realmResource = keycloak.realm(REALM_USE);
UsersResource usersRessource = realmResource.users();
List&lt;UserRepresentation&gt; users = usersRessource.list().stream()
.filter(user -&gt;  user.getUsername().contains(emailSearch))
.collect(Collectors.toList());
UserRepresentation user_ = users.get(0);
UserResource userResource = usersRessource.get(user_.getId());
UserRepresentation consumerUser = userResource.toRepresentation();
consumerUser.setEmail(email);
consumerUser.setFirstName(firstName);
consumerUser.setLastName(Lastname);
userResource.update(consumerUser);
System.out.println(&quot;found:&quot; + users.size() + &quot; &quot; + user_.getId() + &quot; &quot; + user_.getFirstName() + &quot; &quot; + user_.getEmail());
}
}

huangapple
  • 本文由 发表于 2020年8月3日 22:12:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/63231056.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定