7.6. 사용자 및 쿼리 기능 인터페이스 추가/제거
예제에 포함되지 않은 한 가지는 사용자를 추가 및 제거하거나 암호를 변경할 수 있도록 허용하는 것입니다. 예제에 정의된 사용자도 Admin Console에서 쿼리하거나 볼 수 없습니다. 이러한 향상된 기능을 추가하려면 예제 공급자가 UserQueryProvider 및 UserRegistrationProvider 인터페이스를 구현해야 합니다.
7.6.1. Implementing UserRegistrationProvider 링크 복사링크가 클립보드에 복사되었습니다!
이 절차를 사용하여 특정 저장소에서 사용자 추가 및 제거를 구현하려면 먼저 속성 파일을 디스크에 저장할 수 있어야 합니다.
PropertyFileUserStorageProvider
public void save() {
String path = model.getConfig().getFirst("path");
path = EnvUtil.replace(path);
try {
FileOutputStream fos = new FileOutputStream(path);
properties.store(fos, "");
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
그런 다음, addUser() 및 removeUser() 메서드의 구현이 간소화됩니다.
PropertyFileUserStorageProvider
public static final String UNSET_PASSWORD="#$!-UNSET-PASSWORD";
@Override
public UserModel addUser(RealmModel realm, String username) {
synchronized (properties) {
properties.setProperty(username, UNSET_PASSWORD);
save();
}
return createAdapter(realm, username);
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
synchronized (properties) {
if (properties.remove(user.getUsername()) == null) return false;
save();
return true;
}
}
사용자를 추가할 때 속성 맵의 암호 값을 UNSET_PASSWORD 로 설정합니다. 속성 값에 속성에 대한 null 값이 없기 때문에 이 작업을 수행합니다. 또한 이를 반영하기 위해 CredentialInputValidator 방법을 수정해야 합니다.
공급자가 UserRegistrationProvider 인터페이스를 구현하는 경우 addUser() 메서드가 호출됩니다. 공급자에 사용자 추가를 끄는 구성 스위치가 있는 경우 이 메서드에서 null 을 반환하면 공급자를 건너뛰고 다음 항목을 호출합니다.
PropertyFileUserStorageProvider
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
if (!supportsCredentialType(input.getType()) || !(input instanceof UserCredentialModel)) return false;
UserCredentialModel cred = (UserCredentialModel)input;
String password = properties.getProperty(user.getUsername());
if (password == null || UNSET_PASSWORD.equals(password)) return false;
return password.equals(cred.getValue());
}
이제 속성 파일을 저장할 수 있으므로 암호 업데이트를 허용하는 것도 좋습니다.
PropertyFileUserStorageProvider
@Override
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
if (!(input instanceof UserCredentialModel)) return false;
if (!input.getType().equals(CredentialModel.PASSWORD)) return false;
UserCredentialModel cred = (UserCredentialModel)input;
synchronized (properties) {
properties.setProperty(user.getUsername(), cred.getValue());
save();
}
return true;
}
이제 암호 비활성화도 구현할 수 있습니다.
PropertyFileUserStorageProvider
@Override
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
if (!credentialType.equals(CredentialModel.PASSWORD)) return;
synchronized (properties) {
properties.setProperty(user.getUsername(), UNSET_PASSWORD);
save();
}
}
private static final Set<String> disableableTypes = new HashSet<>();
static {
disableableTypes.add(CredentialModel.PASSWORD);
}
@Override
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
return disableableTypes;
}
이러한 방법을 구현하면 Admin Console에서 사용자의 암호를 변경하고 비활성화할 수 있습니다.
7.6.2. UserQueryProvider 구현 링크 복사링크가 클립보드에 복사되었습니다!
UserQueryProvider 를 구현하지 않으면 관리 콘솔은 예제 공급자가 로드한 사용자를 보고 관리할 수 없습니다. 이 인터페이스 구현을 살펴보겠습니다.
PropertyFileUserStorageProvider
@Override
public int getUsersCount(RealmModel realm) {
return properties.size();
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return getUsers(realm, 0, Integer.MAX_VALUE);
}
@Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
List<UserModel> users = new LinkedList<>();
int i = 0;
for (Object obj : properties.keySet()) {
if (i++ < firstResult) continue;
String username = (String)obj;
UserModel user = getUserByUsername(username, realm);
users.add(user);
if (users.size() >= maxResults) break;
}
return users;
}
getUsers() 메서드는 getUserByUsername()이 사용자를 로드하기 위해 속성 파일의 키 집합을 반복하고 getUserByUsername() 에 위임합니다. firstResult 및 maxResults 매개변수를 기반으로 이 호출을 인덱싱하고 있습니다. 외부 저장소에서 페이지 번호를 지원하지 않는 경우 비슷한 논리를 수행해야 합니다.
PropertyFileUserStorageProvider
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE);
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
List<UserModel> users = new LinkedList<>();
int i = 0;
for (Object obj : properties.keySet()) {
String username = (String)obj;
if (!username.contains(search)) continue;
if (i++ < firstResult) continue;
UserModel user = getUserByUsername(username, realm);
users.add(user);
if (users.size() >= maxResults) break;
}
return users;
}
searchForUser() 의 첫 번째 선언에는 String 매개 변수가 사용됩니다. 사용자를 찾기 위해 사용자 이름 및 이메일 속성을 검색하는 데 사용하는 문자열이 되어야 합니다. 이 문자열은 하위 문자열일 수 있으므로 검색을 수행할 때 String.contains() 메서드를 사용합니다.
PropertyFileUserStorageProvider
@Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
return searchForUser(params, realm, 0, Integer.MAX_VALUE);
}
@Override
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
// only support searching by username
String usernameSearchString = params.get("username");
if (usernameSearchString == null) return Collections.EMPTY_LIST;
return searchForUser(usernameSearchString, realm, firstResult, maxResults);
}
Map 매개변수를 사용하는 searchForUser() 메서드는 첫 번째, 성, 사용자 이름, 이메일에 따라 사용자를 검색할 수 있습니다. 사용자 이름만 저장하므로 사용자 이름을 기반으로만 검색합니다. 이를 위해 searchForUser() 에 위임합니다.
PropertyFileUserStorageProvider
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return Collections.EMPTY_LIST;
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
return Collections.EMPTY_LIST;
}
@Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
return Collections.EMPTY_LIST;
}
그룹 또는 특성을 저장하지 않으므로 다른 방법으로는 빈 목록이 반환됩니다.