Activiti 7 how to access the identity management of its own system

Posted by bjoerndalen on Fri, 14 Jan 2022 12:49:49 +0100

1, Official example

First, the official website gives a simple demo example: https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java#L26

I suggest you download the completed demo and have a closer look. Here are the main ideas

 

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

Such key code I

 SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return user.getAuthorities();

The Authentication object is set in the Authentication context. This object returns the permission Authorities collection of the authenticator. This result will be used for judgment later. If there is no ROLE_ACTIVITI_USER} will throw an exception indicating that it is inaccessible.

Such key code 2

org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);

Set the login in the Authentication context. Note that the Authentication here is different from that in the previous Spring SecurityContextHolder, and their package names are different. The thread variable in Authentication in activiti is used to obtain user information later. For example, set the initiator and the task of the current user.

2 configuration class

@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

Injects the user service InMemoryUserDetailsManager, and creates two new users, system, admin, with corresponding roles. Please note the ROLE_ACTIVITI_ADMIN users will not be able to access and invoke the relevant APIs.

 

2, Access Custom identity

 

According to the above two points, we can transform and access our own identity system.

 

1 user

1) ActivitiUserDetailsManager

UserDetailsService will inject our own identity service ActivitiUserDetailsManager. We can imitate the InMemoryUserDetailsManager class for its implementation. The key code is to rewrite the following methods:

@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")));
    }

among

BizUserEntity bizUser = userService.getBizUserById(userId);

This is the identity service query method in your own business, and this object is transformed into the following users

org.springframework.security.core.userdetails.User;

And have role_ ACTIVITI_ The role of user.

 

2 configuration class

Like the demo, just inject UserDetailsService.

@Bean
public UserDetailsService activitiUserDetailsService() {
    return new ActivitiUserDetailsManager(userService,groupManager);
}

This time, the parameter {userService and groupmanager are the user / group management services of your own business system. I passed them in here through the constructor. You can also inject them in other ways. To put it bluntly, the ActivitiUserDetailsManager class simply wraps your own userService, which can be decoupled from the user service of the workflow.

2 user groups

Wait, the above case only illustrates user query, but what about user groups? In fact, activiti 7 has a default implementation

org.activiti.core.common.spring.identity.ActivitiUserGroupManagerImpl

Among them, there are two most important methods: obtaining user groups and obtaining user roles

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());
}

In fact, this is also done through the user query userDetailsService, and the role is queried through prefix matching, GROUP_ It is not difficult to understand the following code in the demo

{"system", "password", "ROLE_ACTIVITI_USER"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"}

Therefore, copy the implementation of ActivitiUserGroupManagerImpl and create a new implementation of ActivitiGroupManagerImpl

org.activiti.api.runtime.shared.identity.UserGroupManager

Just rewrite the relevant methods. It is worth noting that the @ Primary annotation needs to be added

 

Because the default ActivitiUserGroupManagerImpl is also automatically initialized by spring, plus @Primary This is to tell spring to use ActivitiGroupManagerImpl when there are multiple implementation classes shi.

At this point, you can fully access your identity system, including the ability of users and user groups. For the versions below activiti7, the implementation will be very different, but the official document gives the solution, as shown below:

https://www.activiti.org/userguide/index.html#advanced.custom.session.manager

 

https://my.oschina.net/woniuyi/blog/4714756