Spring Securityを使用したActiviti
1. 概要
Activitiは、オープンソースのBPM(ビジネスプロセス管理)システムです。 はじめに、Guide to Activiti with Javaを確認してください。
ActivitiとSpringフレームワークの両方が独自のID管理を提供します。 ただし、in an application that integrates both projects, we may want to combine the two into a single user management process.
以下では、これを実現するための2つの可能性について説明します。1つはSpring SecurityにActivitiがサポートするユーザーサービスを提供する方法で、もう1つはSpringSecurityユーザーソースをActivitiID管理にプラグインする方法です。
2. Mavenの依存関係
Spring BootプロジェクトでActivitiを設定するには、our previous articleを確認してください。 activiti-spring-boot-starter-basic,に加えて、activiti-spring-boot-starter-securityの依存関係も必要になります。
org.activiti
activiti-spring-boot-starter-security
6.0.0
3. Activitiを使用したID管理
このシナリオでは、Activitiスターターは、HTTP Basic認証ですべてのRESTエンドポイントを保護するSpringBoot自動構成クラスを提供します。
自動構成では、クラスIdentityServiceUserDetailsService.のUserDetailsServiceBeanも作成されます。
このクラスは、SpringインターフェイスUserDetailsServiceを実装し、loadUserByUsername()メソッドをオーバーライドします。 このメソッドは、指定されたidを持つActivitiUserオブジェクトを取得し、それを使用してSpringUserDetailsオブジェクトを作成します。
また、ActivitiGroupオブジェクトはSpringユーザーロールに対応します。
これは、Spring Securityアプリケーションにログインするときに、Activiti資格情報を使用することを意味します。
3.1. Activitiユーザーの設定
まず、IdentityService:を使用して、メインの@SpringBootApplicationクラスで定義されたInitializingBeanにユーザーを作成しましょう。
@Bean
InitializingBean usersAndGroupsInitializer(IdentityService identityService) {
return new InitializingBean() {
public void afterPropertiesSet() throws Exception {
User user = identityService.newUser("activiti_user");
user.setPassword("pass");
identityService.saveUser(user);
Group group = identityService.newGroup("user");
group.setName("ROLE_USER");
group.setType("USER");
identityService.saveGroup(group);
identityService.createMembership(user.getId(), group.getId());
}
};
}
since this will be used by Spring Security, the Group object name has to be of the form “ROLE_X”.に気付くでしょう
3.2. Spring Securityの構成
HTTP基本認証の代わりに別のセキュリティ構成を使用する場合は、最初に自動構成を除外する必要があります。
@SpringBootApplication(
exclude = org.activiti.spring.boot.SecurityAutoConfiguration.class)
public class ActivitiSpringSecurityApplication {
// ...
}
次に、IdentityServiceUserDetailsServiceを使用してActivitiデータソースからユーザーを取得する独自のSpringSecurity構成クラスを提供できます。
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IdentityService identityService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService());
}
@Bean
public UserDetailsService userDetailsService() {
return new IdentityServiceUserDetailsService(
this.identityService);
}
// spring security configuration
}
4. SpringSecurityを使用したID管理
Spring Securityを使用してユーザー管理を既に設定していて、アプリケーションにActivitiを追加する場合は、ActivitiのID管理をカスタマイズする必要があります。
この目的のために、拡張する必要のある2つの主要なクラスがあります。ユーザーとグループを処理するUserEntityManagerImplとGroupEntityManagerImplです。
これらのそれぞれについて詳しく見ていきましょう。
4.1. UserEntityManagerImplの拡張
UserEntityManagerImplクラスを拡張する独自のクラスを作成しましょう。
public class SpringSecurityUserManager extends UserEntityManagerImpl {
private JdbcUserDetailsManager userManager;
public SpringSecurityUserManager(
ProcessEngineConfigurationImpl processEngineConfiguration,
UserDataManager userDataManager,
JdbcUserDetailsManager userManager) {
super(processEngineConfiguration, userDataManager);
this.userManager = userManager;
}
// ...
}
このクラスには、上記の形式のコンストラクターとSpring Securityユーザーマネージャーが必要です。 この例では、データベースに裏打ちされたUserDetailsManager.を使用しました
オーバーライドする主なメソッドは、ユーザー検索を処理するメソッドです:findById(),findUserByQueryCriteria()およびfindGroupsByUser().
findById()メソッドは、JdbcUserDetailsManagerを使用してUserDetailsオブジェクトを検索し、それをUserオブジェクトに変換します。
@Override
public UserEntity findById(String userId) {
UserDetails userDetails = userManager.loadUserByUsername(userId);
if (userDetails != null) {
UserEntityImpl user = new UserEntityImpl();
user.setId(userId);
return user;
}
return null;
}
次に、findGroupsByUser()メソッドは、ユーザーのすべてのSpring Security権限を検索し、GroupオブジェクトのListを返します。
public List findGroupsByUser(String userId) {
UserDetails userDetails = userManager.loadUserByUsername(userId);
if (userDetails != null) {
return userDetails.getAuthorities().stream()
.map(a -> {
Group g = new GroupEntityImpl();
g.setId(a.getAuthority());
return g;
})
.collect(Collectors.toList());
}
return null;
}
findUserByQueryCriteria()メソッドは、複数のプロパティを持つUserQueryImplオブジェクトに基づいており、Spring Securityに対応するものがあるため、そこからグループIDとユーザーIDを抽出します。
@Override
public List findUserByQueryCriteria(
UserQueryImpl query, Page page) {
// ...
}
このメソッドは、UserDetailsオブジェクトからUserオブジェクトを作成することにより、上記のメソッドと同様の原則に従います。 完全な実装については、最後のGitHubリンクを参照してください。
同様に、findUserCountByQueryCriteria()メソッドがあります。
public long findUserCountByQueryCriteria(
UserQueryImpl query) {
return findUserByQueryCriteria(query, null).size();
}
パスワードの検証はActivitiによって行われないため、checkPassword()メソッドは常にtrueを返す必要があります。
@Override
public Boolean checkPassword(String userId, String password) {
return true;
}
ユーザーの更新を処理する方法など、他の方法の場合、これはSpring Securityによって処理されるため、例外をスローします。
public User createNewUser(String userId) {
throw new UnsupportedOperationException("This operation is not supported!");
}
4.2. GroupEntityManagerImplを拡張する
SpringSecurityGroupManagerは、ユーザーグループを処理するという事実を除いて、ユーザーマネージャークラスに似ています。
public class SpringSecurityGroupManager extends GroupEntityManagerImpl {
private JdbcUserDetailsManager userManager;
public SpringSecurityGroupManager(ProcessEngineConfigurationImpl
processEngineConfiguration, GroupDataManager groupDataManager) {
super(processEngineConfiguration, groupDataManager);
}
// ...
}
ここでthe main method to override is the findGroupsByUser() method:
@Override
public List findGroupsByUser(String userId) {
UserDetails userDetails = userManager.loadUserByUsername(userId);
if (userDetails != null) {
return userDetails.getAuthorities().stream()
.map(a -> {
Group g = new GroupEntityImpl();
g.setId(a.getAuthority());
return g;
})
.collect(Collectors.toList());
}
return null;
}
このメソッドは、Spring Securityユーザーの権限を取得し、それらをGroupオブジェクトのリストに変換します。
これに基づいて、findGroupByQueryCriteria()およびfindGroupByQueryCriteriaCount()メソッドをオーバーライドすることもできます。
@Override
public List findGroupByQueryCriteria(GroupQueryImpl query, Page page) {
if (query.getUserId() != null) {
return findGroupsByUser(query.getUserId());
}
return null;
}
@Override
public long findGroupCountByQueryCriteria(GroupQueryImpl query) {
return findGroupByQueryCriteria(query, null).size();
}
グループを更新する他のメソッドをオーバーライドして、例外をスローできます。
public Group createNewGroup(String groupId) {
throw new UnsupportedOperationException("This operation is not supported!");
}
4.3. プロセスエンジンの構成
2つのIDマネージャークラスを定義したら、それらを構成に配線する必要があります。
スプリングスターターは、SpringProcessEngineConfigurationを自動構成します。 これを変更するには、InitializingBean:を使用する。
@Autowired
private SpringProcessEngineConfiguration processEngineConfiguration;
@Autowired
private JdbcUserDetailsManager userManager;
@Bean
InitializingBean processEngineInitializer() {
return new InitializingBean() {
public void afterPropertiesSet() throws Exception {
processEngineConfiguration.setUserEntityManager(
new SpringSecurityUserManager(processEngineConfiguration,
new MybatisUserDataManager(processEngineConfiguration), userManager));
processEngineConfiguration.setGroupEntityManager(
new SpringSecurityGroupManager(processEngineConfiguration,
new MybatisGroupDataManager(processEngineConfiguration)));
}
};
}
ここでは、既存のprocessEngineConfigurationが、カスタムIDマネージャーを使用するように変更されています。
Activitiで現在のユーザーを設定する場合、次のメソッドを使用できます。
identityService.setAuthenticatedUserId(userId);
これによりThreadLocalプロパティが設定されるため、値はスレッドごとに異なることに注意してください。
5. 結論
この記事では、ActivitiをSpringSecurityと統合する2つの方法を見てきました。
完全なソースコードはover on GitHubにあります。