RBAC Role-based Access Control model

Metadata management and business data processing have been mainly introduced before. Usually, a system has multiple users, and different users have different permissions. This article mainly introduces the implementation of rBAC-based dynamic permission management in CrudAPI.

The profile

RBAC profile

Role-based Access Control (RBAC) refers to role-based Access Control. There are several key terms in the model: User: Operator rights for the system interface and access: authorization to access an interface or perform an operation role: a general term for a user who has the same class of operation rights

Rights of user roles

A user has one or more roles. A role contains multiple users. A role has multiple permissions

Spring security

Spring Security is a framework used by the Spring project team to provide Security authentication services, which can easily implement dynamic permission management.

Form the configuration

System built-in 5 forms, these forms and permissions related, and the specific business is irrelevant

Resources in the resource

The URL is an ANT format expression that is used to configure the URL to determine whether you have permission to a resource.

User user

User table Records the login user information

Role role

role

The user role row is userRoleLine

Intermediate table of users and roles, refer to previous table relationship management, use two one-to-many to establish many-to-many relationship,

RoleResourceLine roleResourceLine

An intermediate table of roles and resources, again using two one-to-many relationships to establish a many-to-many relationship

Table relationships

The original table The target table Relationship between
user userRoleLine More than a pair of
userRoleLine role For one more
role roleResourceLine More than a pair of
roleResourceLine resource For one more

Principle of Permission Control

The user can obtain the role list based on the login user’s preference. Each role corresponds to multiple resources, and the end user’s permission is the superposition of the resources corresponding to the multiple roles. Return data if you have permission to a resource, otherwise a message is displayed indicating no permission. By default, if no resource is matched, only the login user is required for the resource.

validation

To add a customer resource, set the ANT URL to/API /business/customer/** and the operation to *, indicating that GET, PATCH, DELETE, and POST all require authorization. If the operation is DELETE, the value controls the DELETE operation and other operations are not restricted.

When accessing a client through the UI, the message “no permission” is displayed, as expected

Add the role Customer Administrator, which has the access rights of customers

Add the customer administrator role to the super administrator. Then the super administrator has the customer access rights

The user needs to log out and log in again. After the login, the user can access the customer resources.

The core source

@Slf4j
@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static Map<String, ConfigAttribute> configAttributeMap = null;
    
    @Autowired
    private DynamicSecurityService dynamicSecurityService;

    @PostConstruct
    public void loadDataSource(a) {
        configAttributeMap = dynamicSecurityService.loadDataSource();
    }

    public void clearDataSource(a) {
        log.info("DynamicSecurityMetadataSource clearDataSource");
        configAttributeMap.clear();
        configAttributeMap = null;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        if (configAttributeMap == null)  {
            this.loadDataSource();
        }
        List<ConfigAttribute>  configAttributes = new ArrayList<>();
        
        FilterInvocation fi = (FilterInvocation) o;
        
        String method = fi.getRequest().getMethod();
        log.info("getAttributes method = " + method);
        
        // Get the current access path
        String url = fi.getRequestUrl();
        String path = URLUtil.getPath(url) + "_"+ method;
        
        log.info("getAttributes url = " + url);
        log.info("getAttributes path = " + path);
        
        PathMatcher pathMatcher = new AntPathMatcher();
        Iterator<String> iterator = configAttributeMap.keySet().iterator();
        // Get the resources needed to access the path
        while (iterator.hasNext()) {
            String pattern = iterator.next();
            if (pathMatcher.match(pattern, path)) {
                log.info("match success = " + pattern + ","+ path); configAttributes.add(configAttributeMap.get(pattern)); }}// An empty set is returned
        return configAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes(a) {
        return null;
    }

    @Override
    public boolean supports(Class
        aClass) {
        return true; }}Copy the code

Inheritance FilterInvocationSecurityMetadataSource, realize the getAttributes interface, through HTTP url and HTTP method match

@Slf4j
@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {

    @Override
    public void decide(Authentication authentication, Object object, Collection
       
         configAttributes)
        throws AccessDeniedException, InsufficientAuthenticationException {
        // If no resources are configured for the interface, the interface is allowed
        if (CollUtil.isEmpty(configAttributes)) {
            log.info("empty configAttributes decide passed!");
            return;
        }
        
        FilterInvocation fi = (FilterInvocation) object;
        
        String method = fi.getRequest().getMethod();
        log.info("decide method = " + method);
        
        List<String> needAuthorityList = new ArrayList<String>();
        
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
        while (iterator.hasNext()) {
            ConfigAttribute configAttribute = iterator.next();
            // Compare the resources needed to access or the resources owned by the user
            String needAuthority = configAttribute.getAttribute();
            needAuthorityList.add(needAuthority);
            for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
                if (needAuthority.trim().equals(grantedAuthority.getAuthority())) {
                    return; }}}throw new AccessDeniedException("Sorry, you don't have the resources:" + String.join(",", needAuthorityList) +"Access to!");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class
        aClass) {
        return true; }}Copy the code

Inherits the AccessDecisionManager, implements the Decide interface, and compares the resources required for accessing or the resources owned by the user. If the user has the permission, the user is allowed; otherwise, the system displays no permission.

summary

This paper introduces the implementation principle of RBAC in CRUDAPI. First, Spring Security framework is introduced, and then forms such as users, roles and resources are generated by configuration. Basic CRUD functions are realized through configuration, and finally dynamic permission refined management is realized. Because the user, role, and other tables have nothing to do with the business, they are used as built-in forms.

Attached the demo presentation

This system is a production-level zero-code platform, which is different from automatic code generator. It does not need to generate business code such as Controller, Service, Repository, Entity, etc. It can be used when the program is running. You can override basic business-neutral CRUD RESTful apis.

Website address: crudapi. Cn test address: demo. Crudapi. Cn/crudapi/log…