修改spring security源码实现动态授权
修改spring security源码实现动态授权博客分类:?- 技术文档SecuritySpringXMLDAO配置管理Java代码??

- spring?security?安全框架都是通过xml配置文件在容器启动时把资源和角色之间的许可信息加载到内存中,可往往我们需要通过在数据库中配置资源和角色的许可管理来实现动态授权,下面介绍一些通过修改springsecurity源代码的方法来实现动态授权。??
- ??
- ???
- ??
- 首先下载spring?security的源代码找到org.springframework.security.intercept.web.FilterSecurityInterceptor类,找到obtainObjectDefinitionSource方法,我们就是要通过修改该方法实现动态授权??
- ??
- ???
- ??
- ???
- ??
- ????private?static?FilterInvocationDefinitionSource?s?=?null;??
- ??
- ????private?ScRoleResDAO?scRoleResDAO;??
- ??
- ????private?ScResourceDAO?scResourceDAO;??
- ??
- ???
- ??
- ????public?ObjectDefinitionSource?obtainObjectDefinitionSource()?{??
- ??
- ???
- ??
- ????if?(s?==?null){??
- ??
- ????????UrlMatcher?urlMatcher?=?new?AntUrlPathMatcher(true);??
- ??
- ????????LinkedHashMap?requestMap?=?new?LinkedHashMap();??
- ??
- ???
- ??
- //??????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext(??
- ??
- //?????????????????"spring/dataAccess.xml"??
- ??
- //?????????????????);??
- ??
- //??????????ScRoleResDAO?scRoleResDAO?=?(ScRoleResDAO)context.getBean("ScRoleResDAO");??
- ??
- //???????????ScResourceDAO?scResourceDAO?=?(ScResourceDAO)context.getBean("ScResourceDAO");??
- ??
- ???
- ??
- ????????/*?一下这段代码可以忽视,因为每个人的实现方式都不同,?
- ?
- ?????????*?这段代码主要是从数据库中取得资源和角色信息的,?
- ?
- ?????????*?大家取出来的信息格式可能多种多样,关键是要把这些信息整理成统一的格式?
- ?
- ?????????*?参照下面第二段标注为关键代码的部分*/??
- ??
- ????????Map<ScResource,?List<ScRoleRes>>?map?=?new?TreeMap<ScResource,?List<ScRoleRes>>();??
- ??
- ????????ScResourceExample?e?=?new?ScResourceExample();??
- ??
- ????????e.setOrderByClause("ORDER_NUM");??
- ??
- ????????List<ScResource>?resList?=?scResourceDAO.selectByExample(e);??
- ??
- ???
- ??
- ????????ScRoleResExample?example?=?null;??
- ??
- ????????String?url?=?"";??
- ??
- ????????List<ScRoleRes>?list?=?null;??
- ??
- ????????for?(ScResource?resource?:?resList)?{??
- ??
- ????????????url?=?resource.getUrl();??
- ??
- ????????????example?=?new?ScRoleResExample();??
- ??
- ????????????example.createCriteria().andUrlEqualTo(url);??
- ??
- ????????????list?=?scRoleResDAO.selectByExample(example);??
- ??
- ????????????if?(list?!=?null){??
- ??
- ???????????????map.put(resource,?list);??
- ??
- ????????????}??
- ??
- ????????}??
- ??
- ???
- ??
- ???
- ??
- ????????/****************??以下是关键代码?*********************/??
- ??
- ???
- ??
- ????????/*?
- ?
- ?????????*?这段代码的重点是生成?requestMap?
- ?
- ?????????*?requestMap?的?key?的类型为?RequestKey?,需要包含资源的url?
- ?
- ?????????*?requestMap?的?value?的类型为?ConfigAttributeDefinition?,它需要包含该资源可访问的角色列表信息?
- ?
- ?????????*?最后生成?DefaultFilterInvocationDefinitionSource?返回就可以了,?
- ?
- ?????????*?当然需要把这个结果保存在内存中,要不然画面上每次刷新都要从数据库中取得信息,资源消耗太大了?
- ?
- ?????????*?提供一个刷内存的方法,当数据库中的权限信息改变时要刷新内存中的旧的信息*/??
- ??
- ????????????Iterator?iterator?=?map.entrySet().iterator();??
- ??
- ????????????ScResource?key?=?null;??
- ??
- ????????????List<ScRoleRes>?list1?=?null;??
- ??
- ????????????List<ConfigAttribute>?roles?=?null;??
- ??
- ????????????while?(iterator.hasNext())?{??
- ??
- ????????????????Map.Entry?entry?=?(Map.Entry)?iterator.next();??
- ??
- ????????????????key?=?(ScResource)entry.getKey();??
- ??
- ????????????????RequestKey?reqKey?=?new?RequestKey(key.getUrl());??
- ??
- ????????????????list1?=?(List<ScRoleRes>)entry.getValue();??
- ??
- ????????????????roles?=?new?ArrayList<ConfigAttribute>();??
- ??
- ????????????????for?(ScRoleRes?res?:?list1)?{??
- ??
- ??????????????????roles.add(new?SecurityConfig(res.getRole()));??
- ??
- ????????????}??
- ??
- ????????????????requestMap.put(reqKey,?new?ConfigAttributeDefinition(roles));??
- ??
- ????????????}??
- ??
- ????????????s?=?new?DefaultFilterInvocationDefinitionSource(urlMatcher,requestMap);??
- ??
- ????????????/****************??以上是关键代码?*********************/??
- ??
- ????}??
- ??
- ????????return?s;??
- ??
- ????}??
- ??
- ???
- ??
- ????/**?
- ?
- ?????*?提供一个刷新内存的静态方法?
- ?
- ?????*/??
- ??
- ????public?static?void?refresh()?{??
- ??
- ???????s?=?null;??
- ??
- ???
- ??
- ???
- ??
- 修改启动加载的xml文件,如果此文件是通过命名空间配置的,需要加入??
- ??
- ???
- ??
- ????<beans:bean?id="_filterSecurityInterceptor"??
- ??
- ???????class="org.springframework.security.intercept.web.FilterSecurityInterceptor"??
- ??
- ???????p:authenticationManager-ref="_authenticationManager"??
- ??
- ????????p:accessDecisionManager-ref="accessDecisionManager">??
- ??
- ????????<beans:property?name="objectDefinitionSource">??
- ??
- ???????????<beans:value><![CDATA[??
- ??
- ??????????????CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON??
- ??
- ??????????????PATTERN_TYPE_APACHE_ANT??
- ??
- ??????????????/**=ROLE_SUPERVISOR??
- ??
- ???????????]]></beans:value>??
- ??
- ????????</beans:property>??
- ??
- ???????<beans:property?name="scRoleResDAO"?ref="ScRoleResDAO"/>??
- ??
- ???????<beans:property?name="scResourceDAO"?ref="ScResourceDAO"/>??
- ??
- ????</beans:bean>??
- ??
- ???
- ??
- 其中objectDefinitionSource并没有实际意义,因为我们已经修改了源代码,如果不想注入这个,把FilterSecurityInterceptor类中的objectDefinitionSource变量去掉应该就可以了,不过没有试过??
- ??
- 另外两个DAO是我根据我的代码注入的,大家换成自己的DAO就可以了。 ?
?

- spring?security?安全框架都是通过xml配置文件在容器启动时把资源和角色之间的许可信息加载到内存中,可往往我们需要通过在数据库中配置资源和角色的许可管理来实现动态授权,下面介绍一些通过修改springsecurity源代码的方法来实现动态授权。??
- ??
- ???
- ??
- 首先下载spring?security的源代码找到org.springframework.security.intercept.web.FilterSecurityInterceptor类,找到obtainObjectDefinitionSource方法,我们就是要通过修改该方法实现动态授权??
- ??
- ???
- ??
- ???
- ??
- ????private?static?FilterInvocationDefinitionSource?s?=?null;??
- ??
- ????private?ScRoleResDAO?scRoleResDAO;??
- ??
- ????private?ScResourceDAO?scResourceDAO;??
- ??
- ???
- ??
- ????public?ObjectDefinitionSource?obtainObjectDefinitionSource()?{??
- ??
- ???
- ??
- ????if?(s?==?null){??
- ??
- ????????UrlMatcher?urlMatcher?=?new?AntUrlPathMatcher(true);??
- ??
- ????????LinkedHashMap?requestMap?=?new?LinkedHashMap();??
- ??
- ???
- ??
- //??????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext(??
- ??
- //?????????????????"spring/dataAccess.xml"??
- ??
- //?????????????????);??
- ??
- //??????????ScRoleResDAO?scRoleResDAO?=?(ScRoleResDAO)context.getBean("ScRoleResDAO");??
- ??
- //???????????ScResourceDAO?scResourceDAO?=?(ScResourceDAO)context.getBean("ScResourceDAO");??
- ??
- ???
- ??
- ????????/*?一下这段代码可以忽视,因为每个人的实现方式都不同,?
- ?
- ?????????*?这段代码主要是从数据库中取得资源和角色信息的,?
- ?
- ?????????*?大家取出来的信息格式可能多种多样,关键是要把这些信息整理成统一的格式?
- ?
- ?????????*?参照下面第二段标注为关键代码的部分*/??
- ??
- ????????Map<ScResource,?List<ScRoleRes>>?map?=?new?TreeMap<ScResource,?List<ScRoleRes>>();??
- ??
- ????????ScResourceExample?e?=?new?ScResourceExample();??
- ??
- ????????e.setOrderByClause("ORDER_NUM");??
- ??
- ????????List<ScResource>?resList?=?scResourceDAO.selectByExample(e);??
- ??
- ???
- ??
- ????????ScRoleResExample?example?=?null;??
- ??
- ????????String?url?=?"";??
- ??
- ????????List<ScRoleRes>?list?=?null;??
- ??
- ????????for?(ScResource?resource?:?resList)?{??
- ??
- ????????????url?=?resource.getUrl();??
- ??
- ????????????example?=?new?ScRoleResExample();??
- ??
- ????????????example.createCriteria().andUrlEqualTo(url);??
- ??
- ????????????list?=?scRoleResDAO.selectByExample(example);??
- ??
- ????????????if?(list?!=?null){??
- ??
- ???????????????map.put(resource,?list);??
- ??
- ????????????}??
- ??
- ????????}??
- ??
- ???
- ??
- ???
- ??
- ????????/****************??以下是关键代码?*********************/??
- ??
- ???
- ??
- ????????/*?
- ?
- ?????????*?这段代码的重点是生成?requestMap?
- ?
- ?????????*?requestMap?的?key?的类型为?RequestKey?,需要包含资源的url?
- ?
- ?????????*?requestMap?的?value?的类型为?ConfigAttributeDefinition?,它需要包含该资源可访问的角色列表信息?
- ?
- ?????????*?最后生成?DefaultFilterInvocationDefinitionSource?返回就可以了,?
- ?
- ?????????*?当然需要把这个结果保存在内存中,要不然画面上每次刷新都要从数据库中取得信息,资源消耗太大了?
- ?
- ?????????*?提供一个刷内存的方法,当数据库中的权限信息改变时要刷新内存中的旧的信息*/??
- ??
- ????????????Iterator?iterator?=?map.entrySet().iterator();??
- ??
- ????????????ScResource?key?=?null;??
- ??
- ????????????List<ScRoleRes>?list1?=?null;??
- ??
- ????????????List<ConfigAttribute>?roles?=?null;??
- ??
- ????????????while?(iterator.hasNext())?{??
- ??
- ????????????????Map.Entry?entry?=?(Map.Entry)?iterator.next();??
- ??
- ????????????????key?=?(ScResource)entry.getKey();??
- ??
- ????????????????RequestKey?reqKey?=?new?RequestKey(key.getUrl());??
- ??
- ????????????????list1?=?(List<ScRoleRes>)entry.getValue();??
- ??
- ????????????????roles?=?new?ArrayList<ConfigAttribute>();??
- ??
- ????????????????for?(ScRoleRes?res?:?list1)?{??
- ??
- ??????????????????roles.add(new?SecurityConfig(res.getRole()));??
- ??
- ????????????}??
- ??
- ????????????????requestMap.put(reqKey,?new?ConfigAttributeDefinition(roles));??
- ??
- ????????????}??
- ??
- ????????????s?=?new?DefaultFilterInvocationDefinitionSource(urlMatcher,requestMap);??
- ??
- ????????????/****************??以上是关键代码?*********************/??
- ??
- ????}??
- ??
- ????????return?s;??
- ??
- ????}??
- ??
- ???
- ??
- ????/**?
- ?
- ?????*?提供一个刷新内存的静态方法?
- ?
- ?????*/??
- ??
- ????public?static?void?refresh()?{??
- ??
- ???????s?=?null;??
- ??
- ???
- ??
- ???
- ??
- 修改启动加载的xml文件,如果此文件是通过命名空间配置的,需要加入??
- ??
- ???
- ??
- ????<beans:bean?id="_filterSecurityInterceptor"??
- ??
- ???????class="org.springframework.security.intercept.web.FilterSecurityInterceptor"??
- ??
- ???????p:authenticationManager-ref="_authenticationManager"??
- ??
- ????????p:accessDecisionManager-ref="accessDecisionManager">??
- ??
- ????????<beans:property?name="objectDefinitionSource">??
- ??
- ???????????<beans:value><![CDATA[??
- ??
- ??????????????CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON??
- ??
- ??????????????PATTERN_TYPE_APACHE_ANT??
- ??
- ??????????????/**=ROLE_SUPERVISOR??
- ??
- ???????????]]></beans:value>??
- ??
- ????????</beans:property>??
- ??
- ???????<beans:property?name="scRoleResDAO"?ref="ScRoleResDAO"/>??
- ??
- ???????<beans:property?name="scResourceDAO"?ref="ScResourceDAO"/>??
- ??
- ????</beans:bean>??
- ??
- ???
- ??
- 其中objectDefinitionSource并没有实际意义,因为我们已经修改了源代码,如果不想注入这个,把FilterSecurityInterceptor类中的objectDefinitionSource变量去掉应该就可以了,不过没有试过??
- ??
- 另外两个DAO是我根据我的代码注入的,大家换成自己的DAO就可以了。 ?
?