關於 activiti 7 的相關文章,可以參見:
https://my.oschina.net/woniuyi/blog/4700871
所以,我們知道了 activiti 7 沒有身份管理相關的表了,其能力完全和 Spring Security整合。但是也有很多注意事項,下面就具體說下
一、 官方示例
首先,官網給出了簡單了demo 示例:https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java#L26
建議大家將完成的demo下載下來仔細看下。下面說下其主要思路
1 SecurityUtil
@Component
public class SecurityUtil {
@Autowired
private UserDetailsService userDetailsService;
public void logInAs(String username) {
UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
}
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}
@Override
public Object getCredentials() {
return user.getPassword();
}
@Override
public Object getDetails() {
return user;
}
@Override
public Object getPrincipal() {
return user;
}
@Override
public boolean isAuthenticated() {
return true;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username
此類關鍵代碼 一
SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
認證上下文中設置了Authentication 對象,此對象返回了認證者的權限Authorities集合,後面會拿這個結果做判定,如果沒有 ROLE_ACTIVITI_USER 將會拋出異常,提示無法訪問。
此類關鍵代碼 二
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
往 Authentication 上下文中設置了登錄者,注意了,此處的Authentication 和前面Spring SecurityContextHolder 中的不一樣,二者包名不一樣。activiti 中 Authentication中的線程變量用於後面的用戶信息獲取。比如設置發起人,當前用戶的任務等。
2 配置類
@Bean
public UserDetailsService myUserDetailsService() {
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
String[][] usersGroupsAndRoles = {
{"system", "password", "ROLE_ACTIVITI_USER"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"},
};
for (String[] user : usersGroupsAndRoles) {
List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return inMemoryUserDetailsManager
注入了 InMemoryUserDetailsManager 這個用戶服務,新建了兩個用戶 system ,admin,具備相應的角色,請注意 ROLE_ACTIVITI_ADMIN 的用戶將無法訪問調用相關的api 。
二、 接入自定義身份
根據以上兩點,我們就可以改造,並接入自己的身份系統。
1 用戶
1 編寫 ActivitiUserDetailsManager
UserDetailsService 將會注入我們自己的身份服務ActivitiUserDetailsManager。其實現我們仿造InMemoryUserDetailsManager 類即可,關鍵代碼是重寫 如下方法:
@Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
BizUserEntity bizUser = userService.getBizUserById(userId);
return new User(bizUser.getName(), "", Collections.singletonList(new SimpleGrantedAuthority("ROLE_ACTIVITI_USER")));
}
其中
BizUserEntity bizUser = userService.getBizUserById(userId);
這個是自己業務中身份服務查詢方法,並且將此對象轉換爲如下用戶
org.springframework.security.core.userdetails.User;
並且具備ROLE_ACTIVITI_USER 這個角色。
2 配置類
和demo一樣,注入UserDetailsService 即可。
@Bean
public UserDetailsService activitiUserDetailsService() {
return new ActivitiUserDetailsManager(userService,groupManager);
}
2 用戶組
等等,以上的案例只是說明了用戶查詢,但是用戶組呢?其實activiti 7 中,有默認的實現
org.activiti.core.common.spring.identity.ActivitiUserGroupManagerImpl
其中,有兩個最重要的方法:獲取用戶組,獲取用戶角色
public List<String> getUserGroups(String username) {
return (List)this.userDetailsService.loadUserByUsername(username).getAuthorities().stream().filter((a) -> {
return a.getAuthority().startsWith("GROUP_");
}).map((a) -> {
return a.getAuthority().substring(6);
}).collect(Collectors.toList());
}
public List<String> getUserRoles(String username) {
return (List)this.userDetailsService.loadUserByUsername(username).getAuthorities().stream().filter((a) -> {
return a.getAuthority().startsWith("ROLE_");
}).map((a) -> {
return a.getAuthority().substring(5);
}).collect(Collectors.toList());
}
這裏其實也是通過userDetailsService 這個用戶查詢來做的,並且 是通過前綴匹配去查詢 ROLE_ , GROUP_ 的字符串,到這裏也就不難理解demo中如下代碼了
{"system", "password", "ROLE_ACTIVITI_USER"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"}
因此,仿造ActivitiUserGroupManagerImpl 的實現,新建 ActivitiGroupManagerImpl 實現
org.activiti.api.runtime.shared.identity.UserGroupManager
重寫相關的方法即可。值得注意的一點是,需要加上@Primary這個註解
因爲 默認的 ActivitiUserGroupManagerImpl 也是自動交給spring初始化了,加上@Primary 就是告訴spring 當有多個 實現類shi,用ActivitiGroupManagerImpl 這個類。
到此,就完全接入自己的身份系統了,包含用戶和用戶組的能力。對於 activiti7 以下的版本,實現會有很大的差異,但是官方文檔給出瞭解決方案,參見如下:
https://www.activiti.org/userguide/index.html#advanced.custom.session.manager