当前位置 博文首页 > 无限迭代中......:Spring Security——基于读写锁的动态权限配

    无限迭代中......:Spring Security——基于读写锁的动态权限配

    作者:[db:作者] 时间:2021-07-19 19:22

    问题描述

    每次都加载资源,效率低下。

    解决方案

    /**
     * @author ShenTuZhiGang
     * @version 1.2.0
     * @date 2020-03-07 21:57
     */
    @Slf4j
    @Component
    public class CustomFilterInvocationSecurityMetadataSource
            implements FilterInvocationSecurityMetadataSource {
    
        private final IResourceService iResourceService;
    
        private final IRoleService iRoleService;
    
        private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    
        private final Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = new HashMap<>();
        /**
         * 适用于很多线程从一个数据结构读取数据而很少的线程修改其中数据
         */
        ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        /**
         * 该锁可以被多个读操作共用的读锁,但会排斥写操作
         */
        Lock readLock = rwl.readLock();
        /**
         * 该锁排斥所有其他的读操作和写操作
         */
        Lock writeLock = rwl.writeLock();
    
        public CustomFilterInvocationSecurityMetadataSource(IResourceService iResourceService,
                                                            IRoleService iRoleService) {
            this.iResourceService = iResourceService;
            this.iRoleService = iRoleService;
            this.loadResourcePermission();
        }
    
        /**
         * 加载权限
         */
        private void loadResourcePermission() {
            writeLock.lock(); //locks all readers and writers
            try{
                // do write data
                log.info("加载权限");
                requestMap.clear();
                List<Resource> resources = iResourceService.list();
                for (Resource resource : resources) {
                    List<Role> roles = iRoleService.listRoleBySid(resource.getId());
                    String[] roleArr = new String[roles.size()];
                    for (int i = 0; i < roleArr.length; i++) {
                        roleArr[i] = roles.get(i).getName();
                    }
                    requestMap.put(new AntPathRequestMatcher(resource.getPattern()),
                            SecurityConfig.createList(roleArr));
                }
            }finally {
                writeLock.unlock();
            }
        }
    
        /**
         * 权限重载
         */
        public void resetResourcePermission(){
            log.info("权限重载");
            loadResourcePermission();
        }
    
        @Override
        public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
            Set<ConfigAttribute> attributes = new HashSet<>();
            readLock.lock(); //blocks writers only
            try{
                //there should be data now
                final HttpServletRequest request = ((FilterInvocation) o).getRequest();
                for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
                        .entrySet()) {
                    if (entry.getKey().matches(request)) {
                        attributes.addAll(entry.getValue());
                    }
                }
            }finally {
                readLock.unlock();
            }
    //        final String requestUrl = ((FilterInvocation) o).getRequestUrl();
    //        List<Resource> resources = iResourceService.list();
    //        Set<ConfigAttribute> attributes = new HashSet<>();
    //        for (Resource resource : resources) {
    //            if (antPathMatcher.match(resource.getPattern(), requestUrl)) {
    //                List<Role> roles = iRoleService.listRoleBySid(resource.getId());
    //                if (roles.size() > 0) {
    //                    String[] roleArr = new String[roles.size()];
    //                    for (int i = 0; i < roleArr.length; i++) {
    //                        roleArr[i] = roles.get(i).getName();
    //                    }
    //                    attributes.addAll(SecurityConfig.createList(roleArr));
    //                }
    //            }
    //        }
            if (attributes.size() == 0) {
                attributes.addAll(SecurityConfig.createList("ROLE_LOGIN"));
            }
            return attributes;
        }
    
        @Override
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            Set<ConfigAttribute> allAttributes = new HashSet<>();
            readLock.lock(); //blocks writers only
            try{
                for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
                        .entrySet()) {
                    allAttributes.addAll(entry.getValue());
                }
            }finally {
                readLock.unlock();
            }
            return allAttributes;
        }
    
        @Override
        public boolean supports(Class<?> aClass) {
            return FilterInvocation.class.isAssignableFrom(aClass);
        }
    }
    

    参考文章

    Spring Boot2 总结(四) Spring Security 动态权限配置

    cs