6.7. ユーザーおよびクエリー機能インターフェイスの追加/削除
今回の例で対応していない内容の 1 つとして、ユーザーやパスワードの追加および削除を可能にする操作です。また、この例で定義されたユーザーは、管理コンソールでクエリーや表示ができません。このような拡張機能を追加するには、example プロバイダーが UserQueryMethodsProvider インターフェイス (または UserQueryProvider) および UserRegistrationProviderインターフェイスを実装する必要があります。
6.7.1. 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(PasswordCredentialModel.TYPE)) 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(PasswordCredentialModel.TYPE)) return;
synchronized (properties) {
properties.setProperty(user.getUsername(), UNSET_PASSWORD);
save();
}
}
private static final Set<String> disableableTypes = new HashSet<>();
static {
disableableTypes.add(PasswordCredentialModel.TYPE);
}
@Override
public Stream<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
return disableableTypes.stream();
}
これらのメソッドを実装すると、管理コンソールでユーザーのパスワードを変更および無効化できるようになりました。
6.7.2. UserQueryProvider の実装 リンクのコピーリンクがクリップボードにコピーされました!
UserQueryProvider は、UserQueryMethodsProvider と UserCountMethodsProvider を組み合わせたものです。UserQueryMethodsProvider を実装しないと、管理コンソールは example プロバイダーによって読み込まれたユーザーを表示および管理できません。このインターフェイスの実装を見てみましょう。
PropertyFileUserStorageProvider
@Override
public int getUsersCount(RealmModel realm) {
return properties.size();
}
@Override
public Stream<UserModel> searchForUserStream(RealmModel realm, String search, Integer firstResult, Integer maxResults) {
Predicate<String> predicate = "*".equals(search) ? username -> true : username -> username.contains(search);
return properties.keySet().stream()
.map(String.class::cast)
.filter(predicate)
.skip(firstResult)
.map(username -> getUserByUsername(realm, username))
.limit(maxResults);
}
searchForUserStream() の最初の宣言は、String パラメーターを受け取ります。この例では、パラメーターは検索に使用するユーザー名を表します。この文字列は部分文字列にすることができます。そのため、検索を行う際には String.contains() メソッドを選択します。すべてのユーザーのリストを要求することを示すために * を使用していることに注目してください。このメソッドはプロパティーファイルのキーセットを繰り返し処理し、getUserByUsername() にユーザーを読み込みます。firstResult パラメーターおよび maxResults パラメーターに基づいてこの呼び出しにインデックス化していることに留意してください。外部ストアがページネーションをサポートしない場合には、同様のロジックを実行する必要があります。
PropertyFileUserStorageProvider
@Override
public Stream<UserModel> searchForUserStream(RealmModel realm, Map<String, String> params, Integer firstResult, Integer maxResults) {
// only support searching by username
String usernameSearchString = params.get("username");
if (usernameSearchString != null)
return searchForUserStream(realm, usernameSearchString, firstResult, maxResults);
// if we are not searching by username, return all users
return searchForUserStream(realm, "*", firstResult, maxResults);
}
Map パラメーターを取る searchForUserStream() メソッドは、姓名、ユーザー名、およびメールに基づいてユーザーを検索できます。ユーザー名のみが保存されるため、Map パラメーターに username 属性が含まれていない場合を除き、検索はユーザー名のみに基づいて行われます。この場合、すべてのユーザーが返されます。このような場合、searchForUserStream(realm, search, firstResult, maxResults) が使用されます。
PropertyFileUserStorageProvider
@Override
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, Integer firstResult, Integer maxResults) {
return Stream.empty();
}
@Override
public Stream<UserModel> searchForUserByUserAttributeStream(RealmModel realm, String attrName, String attrValue) {
return Stream.empty();
}
グループまたは属性は保存されないため、他のメソッドは空のストリームを返します。