shiro实现动态权限管理

用到shiro框架实现权限控制时,根据实际要求,权限在数据库增删改后都要把权限过滤链变化实时更新到服务器中。

1、配置文件里配置的filterchains都是静态的,但实际开发中更多的是从数据库中动态的获取filterchains。

我们都知道ShiroFilterFactoryBean中的setFilterChainDefinitions()是读取配置文件里默认的filterchains,所以我们的思路是重写这个方法,才能达到我们想要的目的:

public class ShiroPermissionFactory extends ShiroFilterFactoryBean {


    private PermissService permissService;

    /**记录配置中的过滤链*/
    public static String definition="";

    public PermissService getPermissService() {
        return permissService;
    }

    public void setPermissService(PermissService permissService){
        this.permissService = permissService;
    }

    /**
     * 初始化设置过滤链
     */
    @Override
    public void setFilterChainDefinitions(String definitions) {
        definition = definitions;//记录配置的静态过滤链
        List permissions = permissService.findAll();
        Map otherChains = new HashMap();
        permissions.forEach(permiss->{
            //perms.add(e)
                otherChains.put(permiss.getPermissionUrl(), permiss.getPermissionvalue());
        });
           //加载配置默认的过滤链
            Ini ini = new Ini();
            ini.load(definitions);
            Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
            if (CollectionUtils.isEmpty(section)) {
                section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
            }
           //加上数据库中过滤链
            section.putAll(otherChains);
            setFilterChainDefinitionMap(section);
    }

}

这里定义的一个静态属性definition,作用是记录下配置文件中的filterchains,这个属性在等下更新权限的时候会用到。

配置文件如下:

 
        <bean id="shiroFilter" class="com.qsblgs.util.ShiroPermissionFactory">
        <property name="permissService" ref="permissService"/>
        <property name="securityManager" ref="securityManager"/>  
        <property name="loginUrl" value="/login" />
        <property name="successUrl" value="/index" />  
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>  
        <property name="filters">            
            <util:map>  
                <entry key="session">
                    <bean class="com.qsblgs.system.filter.SessionFilter" />
                entry>
                <entry key="captchaAuthc">
                    <bean class="com.qsblgs.system.filter.CaptchaFormAuthenticationFilter">
                        <property name="allowLoginNum" value="3" />
                        <property name="cookiePath" value="/qsbl" />
                        <property name="cookieDomain" value="localhost" />
                    bean>
                entry>
                <entry key="anyRole">
                    <bean class="com.qsblgs.system.filter.AnyRolesFilter" />
                entry>
            util:map>              
        property>
        <property name="filterChainDefinitions">  
            <value>  
                /index.jsp = anon  
                /css/login.css = anon
                /jeasyui/** = anon   
                /bootstrap/** = anon
                /common/** = anon           
                /unauthorized.jsp = anon  
                /security = anon
                /login = captchaAuthc
                /logout = logout
            value>  
        property>  
    bean>

2、系统管理员在后台更新权限(增删改)的时候,要保证数据库中的filterchains同步到服务器中。

@Service("filterChainDefinitionsService")
public class FilterChainDefinitionsServiceImpl implements FilterChainDefinitionsService {

    @Autowired
    private ShiroPermissionFactory permissFactory;

    @Override
    public void reloadFilterChains() {
        synchronized (permissFactory) {   //强制同步,控制线程安全
            AbstractShiroFilter shiroFilter = null;

            try {
                shiroFilter = (AbstractShiroFilter) permissFactory.getObject();

                PathMatchingFilterChainResolver resolver = (PathMatchingFilterChainResolver) shiroFilter
                        .getFilterChainResolver();
                // 过滤管理器
                DefaultFilterChainManager manager = (DefaultFilterChainManager) resolver.getFilterChainManager();
                // 清除权限配置
                manager.getFilterChains().clear();
                permissFactory.getFilterChainDefinitionMap().clear();
                // 重新设置权限
                permissFactory.setFilterChainDefinitions(ShiroPermissionFactory.definition);//传入配置中的filterchains

                Map chains = permissFactory.getFilterChainDefinitionMap();
                //重新生成过滤链
                if (!CollectionUtils.isEmpty(chains)) {
                    chains.forEach((url, definitionChains) -> {
                        manager.createChain(url, definitionChains.trim().replace(" ", ""));
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

这里要注意线程安全控制,用synchronized关键字。同时,可以看到前面的静态属性definition这里就派上用场了。

3、在更新权限时调用reloadFilterChains(),重新加载过滤链:

@Autowired
    private FilterChainDefinitionsService definitionService;

    /**
     * 保存权限
     */
    @SuppressWarnings("unchecked")
    public Permission save(Permission permission){
        Permission perm = super.save(permission);
        definitionService.reloadFilterChains();//保存权限时进行重新加载权限过滤链
        return perm;
    }

    /**
     * 删除权限
     */
    public void delete(Integer pid){
        super.delete(pid);
        definitionService.reloadFilterChains();//重新加载权限过滤链
    }

这样就可以动态的更新权限了。shiro也是本人初学,不知是否有漏洞地方,请大家批评指导~

你可能感兴趣的:(shiro)