Spring下的权限框架 spring security总结
来源:互联网 发布:得力33068 软件下载 编辑:程序博客网 时间:2024/05/20 15:10
Spring下的权限框架 spring security总结
Java代码
- spring
security总结 - 首先导入spring
security所需要的jar包 - spring-security-core-2.0.5.RELEASE.jar
- spring-security-core-tiger-2.0.5.RELEASE.jar
- 一.配置过滤器
- 在web.xml中定义如下过滤器
<filter> <filter-name>springSecurityFilterChai n</filter-name> class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><filter- </filter> <filter-mapping> <filter-name>springSecurityFilterChai n</filter-name> <url-pattern> - CREATE
TABLE `t_account` ( int(11)`id` NOT NULL, 255)`username` varchar( default NULL, 255)`password` varchar( default NULL, int`enabled` default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `t_role` ( int(11)`id` NOT NULL, 255)`name` varchar( default NULL, 255)`descn` varchar( default NULL, PRIMARY KEY (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE
TABLE `t_account_role` ( int(11)`a_id` NOT NULL, int(11)`r_id` NOT NULL, PRIMARY KEY (`a_id`,`r_id`), KEY `FK1C2BC9332D31C656` (`r_id`), KEY `FK1C2BC93371CCC630` (`a_id`), CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY (`a_id`) REFERENCES `t_account` (`id`), CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - insert
into 1,'zhangsan','123',1);t_account values( - insert
into 2,'lisi','321',1);t_account values( - insert
into 1,'系统管理员','ROLE_ADMIN');t_role values( - insert
into 2,'普通用户','ROLE_USER');t_role values( - insert
into 1,2);t_account_role values( 2,1);insert into t_account_role values( - 当用户登录时,spring
security首先判断用户是否可以登录。用户登录后spring security获得该用户的 - 所有权限以判断用户是否可以访问资源。
- spring配置文件中定义
- <authentication-provider>
"dataSource"<jdbc-user-service data-source-ref= "selectusers-by-username-query= username,password,enabled from t_account where username=?" authorities-by-username-query="select r.descn from t_account_role ar join t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where a.username=?"/> </authentication-provider> users-by-username-query:根据用户名查找用户 authorities-by-username-query:根据用户名查找这个用户所有的角色名,将用户访问的URL地址和 "/admin.jsp"查询结果与<intercept-url pattern= access= "ROLE_ADMIN"/>标签进行匹配。 匹配成功就允许访问,否则就返回到提示页面。 在<http>标签中添加登录页面等信息 'true'><http auto-config= "/login.jsp"<intercept-url pattern= access= "IS_AUTHENTICATED_ANONYMOUSLY"/> "/admin.jsp"<intercept-url pattern= access= "ROLE_ADMIN"/> "<intercept-url pattern= - CREATE
TABLE `t_account` ( int(11)`id` NOT NULL, 255)`username` varchar( default NULL, 255)`password` varchar( default NULL, int`enabled` default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `t_role` ( int(11)`id` NOT NULL, 255)`name` varchar( default NULL, 255)`descn` varchar( default NULL, PRIMARY KEY (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE
TABLE `t_account_role` ( int(11)`a_id` NOT NULL, int(11)`r_id` NOT NULL, PRIMARY KEY (`a_id`,`r_id`), KEY `FK1C2BC9332D31C656` (`r_id`), KEY `FK1C2BC93371CCC630` (`a_id`), CONSTRAINT `FK1C2BC93384B0A30E` FOREIGN KEY (`a_id`) REFERENCES `t_account` (`id`), CONSTRAINT `FK1C2BC9332D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE
TABLE `t_module` ( int(11)`id` NOT NULL, 255)`name` varchar( default NULL, 255)`address` varchar( default NULL, PRIMARY KEY (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - CREATE
TABLE `t_module_role` ( int(11)`m_id` NOT NULL, int(11)`r_id` NOT NULL, PRIMARY KEY (`m_id`,`r_id`), KEY `FKA713071E2D31C656` (`r_id`), KEY `FKA713071ED78C9071` (`m_id`), CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY (`m_id`) REFERENCES `t_module` (`id`), CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - insert
into 1,'zhangsan','123',1);t_account values( - insert
into 2,'lisi','321',1);t_account values( - insert
into 1,'系统管理员','ROLE_ADMIN');t_role values( - insert
into 2,'普通用户','ROLE_USER');t_role values( - insert
into 1,2);t_account_role values( 2,1);insert into t_account_role values( 1,'部门管理','/dept.jsp');insert into t_module values( 2,'人员管理','/emp.jsp');insert into t_module values( 1,1);insert into `t_module_role` values( 1,2);insert into `t_module_role` values( 2,1);insert into `t_module_role` values( - 1.在自定义的过滤器中获取资源的URL地址和角色名以取代spring配置文件中原有的<intercept-url
pattern= "/login.jsp"access= "IS_AUTHENTICATED_ANONYMOUSLY"/> 过滤器代码: - import
java.sql.ResultSet; - import
java.sql.SQLException; - import
java.util.LinkedHashMap; - import
java.util.List; - import
java.util.Map; - import
javax.sql.DataSource; - import
org.springframework.beans.factory.FactoryBean; - import
org.springframework.jdbc.core.support.JdbcDaoSupport; - import
org.springframework.jdbc.object.MappingSqlQuery; - import
org.springframework.security.ConfigAttributeDefinitio n; - import
org.springframework.security.ConfigAttributeEditor; - import
org.springframework.security.intercept.web.DefaultFilterInvocationD efinitionSource; - import
org.springframework.security.intercept.web.FilterInvocationDefiniti onSource; - import
org.springframework.security.intercept.web.RequestKey; - import
org.springframework.security.util.AntUrlPathMatcher; - import
org.springframework.security.util.UrlMatcher; - public
class JdbcFilterInvocationDefi nitionSourceFactoryBean extendsJdbcDaoSupport implementsFactoryBean { privateString resourceQuery; publicboolean isSingleton() { returntrue; } publicClass getObjectType() { returnFilterInvocationDefiniti class;onSource. } publicObject getObject() { returnnew DefaultFilterInvocationD thisefinitionSource( this.buildRequestMap());.getUrlMatcher(), } protectedMap<String, String> findResources() { newResourceMapping resourceMapping = ResourceMapping(getDataSource(), resourceQuery); newMap<String, String> resourceMap = LinkedHashMap<String, String>(); for(Resource resource : (List<Resource>) resourceMapping.execute()) { String url = resource.getUrl(); String role = resource.getRole(); if(resourceMap.containsKey(url)) { String value = resourceMap.get(url); ","resourceMap.put(url, value + + role); else} { resourceMap.put(url, role); } } returnresourceMap; } protectedLinkedHashMap<RequestKey, ConfigAttributeDefinitio n> buildRequestMap() { null;LinkedHashMap<RequestKey, ConfigAttributeDefinitio n> requestMap = newrequestMap = LinkedHashMap<RequestKey, ConfigAttributeDefinitio n>(); newConfigAttributeEditor editor = ConfigAttributeEditor(); this.findResources();Map<String, String> resourceMap = for(Map.Entry<String, String> entry : resourceMap.entrySet()) { newRequestKey key = RequestKey(entry.getKey(), null);editor.setAsText(entry.getValue()); requestMap.put(key, (ConfigAttributeDefinitio n) editor.getValue()); } returnrequestMap; } protectedUrlMatcher getUrlMatcher() { returnnew AntUrlPathMatcher(); } publicvoid setResourceQuery(String resourceQuery) { this.resourceQuery= resourceQuery; } privateclass Resource { privateString url; privateString role; publicResource(String url, String role) { this.url= url; this.role= role; } publicString getUrl() { returnurl; } publicString getRole() { returnrole; } } privateclass ResourceMapping extendsMappingSqlQuery { protectedResourceMapping(DataSource dataSource, String resourceQuery) { super(dataSource,resourceQuery); compile(); } protectedObject intmapRow(ResultSet rs, rownum) throwsSQLException { 1);String url = rs.getString( 2);String role = rs.getString( newResource resource = Resource(url, role); returnresource; } } - }
- 将自定义的过滤器放入到原有的spring
security过滤器链中(在spring配置文件中配置) - 定义自定义过滤器(sql语句用于查询资源的URL地址
如:/index.jsp 和角色名 如ROLE_USER) - <beans:bean
id= "filterInvocationDefinitionSource" class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean" > "dataSource"<beans:property name= ref= "dataSource"/> "resourceQuery"<beans:property name= value=" select m.address,r.descn - from
t_module_role mr - join
t_module m on mr.m_id=m.id - join
t_role r on mr.r_id=r.id; "/> </beans:bean> 将自定义过滤器放入过滤器链中 "filterSecurityIntercepto<beans:bean id= r" class="org.springframework.security.intercept.web.FilterSecurityInterceptor" autowire= "byType"> "FILTER_SECURITY_INTERCEPTOR"/><custom-filter before= "objectDefinitionSource"<beans:property name= ref= "filterInvocationDefinitionSource" /> </beans:bean> 2个FilterSecurityIntercepto注意:FilterSecurityIntercepto r过滤器会向request中写入一个标记,用于标记是否已经控制了当前请求,以避免对同一请求多次处理,导致第 r不会再次执行。 在<http>中不需要再定义<intercept-url>,如下: 'true'><http auto-config= "/login.jsp"<form-login login-page= "/error.jsp"authentication-failure-url= default-target-url="/index.jsp"/> </http> 自定义的过滤器就从配置文件中读取sql,查询结果就是角色和资源,用户登录时就在session中保存了用户的角色。 注意:intercept-url的先后顺序,spring security使用第一个能匹配的intercept-url标签进行权限控制。 现在intercept-url来源于数据库,所以在sql查询时注意角色和资源的顺序。 1个字段用于标识顺序,(按从严到宽的顺序)建议在角色和资源的中间表中添加 表结构修改如下: - CREATE
TABLE `t_module_role` ( int(11)`m_id` NOT NULL, int(11)`r_id` NOT NULL, int(11)`priority` default NULL, PRIMARY KEY (`m_id`,`r_id`), KEY `FKA713071E2D31C656` (`r_id`), KEY `FKA713071ED78C9071` (`m_id`), CONSTRAINT `FKA713071ED78C9071` FOREIGN KEY (`m_id`) REFERENCES `t_module` (`id`), CONSTRAINT `FKA713071E2D31C656` FOREIGN KEY (`r_id`) REFERENCES `t_role` (`id`) - )
ENGINE=InnoDB DEFAULT CHARSET=utf8; - 数据如下:
- insert
into 1,'zhangsan','123',1);t_account values( - insert
into 2,'lisi','321',1);t_account values( - insert
into 1,'系统管理员','ROLE_ADMIN');t_role values( - insert
into 2,'普通用户','ROLE_USER');t_role values( - insert
into 1,2);t_account_role values( 2,1);insert into t_account_role values( 1,'部门管理','/dept.jsp');insert into t_module values( 2,'人员管理','/emp.jsp');insert into t_module values( 1,1,3);insert into `t_module_role` values( 1,2,2);insert into `t_module_role` values( 2,1,1);insert into `t_module_role` values( 自定义过滤器修改如下: "filterInvocationDefiniti<beans:bean id= onSource" class="com.lovo.JdbcFilterInvocationDefinitionSourceFactoryBean" > "dataSource"<beans:property name= ref= "dataSource"/> "resourceQuery"<beans:property name= value=" select m.address,r.descn - from
t_module_role mr - join
t_module m on mr.m_id=m.id - join
t_role r on mr.r_id=r.id - order
by mr.priority "/> </beans:bean> 1个hibernateTemplate.如果持久层使用的是hibernate,那么只需要给自定义过滤器注入 在自定义过滤器中就不需要再使用mapRow的方式。而是直接获取url和角色名即可。 例如: publicclass ModuleFilter implementsFactoryBean { - private
String resourceQuery; publicboolean isSingleton() { returntrue; } publicClass getObjectType() { returnFilterInvocationDefiniti class;onSource. } publicObject getObject() { returnnew DefaultFilterInvocationD thisefinitionSource( this.buildRequestMap());.getUrlMatcher(), } protectedMap<String, String> findResources() { newResourceMapping resourceMapping = ResourceMapping(); newMap<String, String> resourceMap = LinkedHashMap<String, String>(); for(Resource resource : (List<Resource>) resourceMapping.execute()) { String url = resource.getUrl(); String role = resource.getRole(); if(resourceMap.containsKey(url)) { String value = resourceMap.get(url); ","resourceMap.put(url, value + + role); else} { resourceMap.put(url, role); } } returnresourceMap; } protectedLinkedHashMap<RequestKey, ConfigAttributeDefinitio n> buildRequestMap() { null;LinkedHashMap<RequestKey, ConfigAttributeDefinitio n> requestMap = newrequestMap = LinkedHashMap<RequestKey, ConfigAttributeDefinitio n>(); newConfigAttributeEditor editor = ConfigAttributeEditor(); this.findResources();Map<String, String> resourceMap = for(Map.Entry<String, String> entry : resourceMap.entrySet()) { newRequestKey key = RequestKey(entry.getKey(), null);editor.setAsText(entry.getValue()); requestMap.put(key, (ConfigAttributeDefinitio n) editor.getValue()); } returnrequestMap; } protectedUrlMatcher getUrlMatcher() { returnnew AntUrlPathMatcher(); } publicvoid setResourceQuery(String resourceQuery) { this.resourceQuery= resourceQuery; } privateclass Resource { privateString url; privateString role; publicResource(String url, String role) { this.url= url; this.role= role; } publicString getUrl() { returnurl; } publicString getRole() { returnrole; } } privateclass ResourceMapping{ publicList<Resource> execute(){ newList<Resource> rlist = ArrayList<Resource>(); List<Role> list = hibernateTemplate.find(resourceQuery); for(inti= 0;i<list.size();i++){Role role = list.get(i); Set<Module> set = role.getModuleSet(); Iterator<Module> it = set.iterator(); while(it.hasNext()){Module m = it.next(); newResource re = Resource(m.getUrl(),role.getDescn()); rlist.add(re); } } - return
rlist; } } publicvoid setHibernateTemplate(HibernateTemplate hibernateTemplate) { - this.hibernateTemplate
= hibernateTemplate; - }
- private
HibernateTemplate hibernateTemplate; - }
- 而从灵活性的角度考虑,把hql写在配置文件中
- <beans:bean
id= "moduleFilter"class="com.lovo.ModuleFilter"> "resourceQuery"<beans:property name= "fromvalue= com.lovo.po.Role >order by ind" </beans:property> "hibernateTemplate"<beans:property name= ref= "hibernateTemplate"></beans:property> </beans:bean> 问题:系统只会在初始化的时候从数据库中加载信息。无法识别数据库中信息的改变。 解决:每个jsp页面上重新内存 代码:每个jsp页面include如下代码: - <%@page
import="org.springframework.context.ApplicationContext"%> - <%@page
import="org.springframework.web.context.support.WebApplicationContextUti ls" %> - <%@page
import="org.springframework.beans.factory.FactoryBean"%> - <%@page
import="org.springframework.security.intercept.web.FilterSecurityIntercepto r" %> - <%@page
import="org.springframework.security.intercept.web.FilterInvocationDefiniti onSource" %> - <%
ApplicationContext ctx = WebApplicationContextUti ls.getWebApplicationContext (application); "&自定义过滤器的id");FactoryBean factoryBean = (FactoryBean) ctx.getBean( FilterInvocationDefiniti onSource fids = (FilterInvocationDefiniti onSource) factoryBean.getObject(); "filterSecurityInterceptoFilterSecurityIntercepto r filter = (FilterSecurityIntercepto r) ctx.getBean( r" );filter.setObjectDefinitionSourc e(fids); - %>
- 控制用户信息
- 用户密码MD5加密:
- <authentication-provider>
"md5"/><password-encoder hash= "dataSource"<jdbc-user-service data-source-ref= "selectusers-by-username-query= username,password,enabled from t_account where username=?" authorities-by-username-query="select a.username,r.descn from t_account_role ar join t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where a.username=?"/> </authentication-provider> 盐值加密 <authentication-provider> "md5"><password-encoder hash= "username"/><salt-source user-property= </password-encoder> "dataSource"<jdbc-user-service data-source-ref= "selectusers-by-username-query= username,password,enabled from t_account where username=?" authorities-by-username-query="select a.username,r.descn from t_account_role ar join t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where a.username=?"/> </authentication-provider> 用户信息缓存,使用spring内置的ehCache实现 "cacheManager"<beans:bean id= class="org.springframework.cache.ehcache.EhCacheManagerFactoryBea n" ></beans:bean>- <beans:bean
id= "userEhCache"class="org.springframework.cache.ehcache.EhCacheFactoryBean"> - <beans:property
name= "cacheManager"ref= "cacheManager"></beans:property> - <beans:property
name= "cacheName"value= "userCache"></beans:property> - </beans:bean>
- <beans:bean
id= "userCache"class="org.springframework.security.providers.dao.cache.EhCacheBasedUserCache"> - <beans:property
name= "cache"ref= "userEhCache"></beans:property> - </beans:bean>
- 在src目录下新建ehcache.xml
- <ehcache>
"java.io.tmpdir"/><diskStore path= <defaultCache "1000"maxElementsInMemory= "false"eternal= "120"timeToIdleSeconds= "120"timeToLiveSeconds= "true"overflowToDisk= /> <cache "userCache"name= "100"maxElementsInMemory= "false"eternal= "600"timeToIdleSeconds= "3600"timeToLiveSeconds= "true"overflowToDisk= /> - </ehcache>
- 在程序中获取用户信息
- UserDetails
ud = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - String
name = ud.getUsername(); - String
pwd = ud.getPassword(); - GrantedAuthority[]
ga = ud.getAuthorities(); - System.out.println(name
+ ","+ pwd); - for(GrantedAuthority
g : ga){ - System.out.println(g.getAuthority());
- }
- 自定义访问拒绝页面
- <http
auto-config= 'true'access-denied-page= "/error.jsp"> - 访问用户以带参形式访问
- 在资源URL地址后加*
- 如
- insert
into 1,'部门管理','/dept.jsp*');t_module values( 2,'人员管理','/emp.jsp*');insert into t_module values( - 自定义用户接口实现
- 由于将sql写在配置文件中只适用于小型系统,而且不灵活,在大型系统或实体关系复杂时需要自定义用户实现的接口。
- 自定义用户实现需要实现2个接口。
- UserDetails:实体类需要实现的接口。
- UserDetailsService:实体管理类需要实现的接口。
- 配置:
- <!--
实体管理类 --> - <beans:bean
id= "userManager"class="com.lovo.UserManager"></beans:bean> - <authentication-provider
user-service-ref= "userManager"> <!-- "dataSource"<jdbc-user-service data-source-ref= "selectusers-by-username-query= username,password,enabled from t_account where username=?" authorities-by-username-query="select a.username,r.descn from t_account_role ar join t_account a on ar.a_id=a.id join t_role r on ar.r_id=r.id where a.username=?"/> --> </authentication-provider> 原有的通过固定sql语句的获取方式可以抛弃,改为使用user-service-ref属性注入的bean来实现对用户及用户所 拥有的资源的查找。 - 用户注销
- 注销功能由过滤器org.springframework.security.ui.logout.LogoutFilter负责完成。
- <a
href= "${pageContext.request.contextPath}/j_spring_security_logout">注销</a> - 被注销的用户就是当前session中保存的用户,注销后页面自动重定向到default-target-url所指定的页面
- spring
security过滤器体系 - spring
security的一系列功能都是由一串过滤器来完成的。在spring配置文件中配置的<http>标签实际上就是 - 起到默认的过滤器进行声明和配置的作用。
- 管理会话
- 当项目中要求不能使用同一个账号同时登陆,按以下步骤实施
- 1.web.xml添加1个监听器
- <listener>
class>org.springframework.security.ui.session.HttpSessionEventPublishe<listener- r</listener- class></listener> 2.spring配置文件中的<http>标签添加子标签<concurrent-session-control/> 'true'<http auto-config= access-denied-page= "/noview.jsp"> "/login.jsp"<form-login login-page= authentication-failure-url= "/error.jsp"default-target-url="/index.jsp"/> - <concurrent-session-control/>
- </http>
- <concurrent-session-control/>会产生1个
org.springframework.security.concurrent.ConcurrentSessionFilter - 并放在过滤器链的最前面。
- 默认情况下,使用同一账号后登陆的用户会踢出先登陆的用户。
- 如果想禁止第2个用户登录,则设置
- <concurrent-session-control
exception- if-maximum-exceeded="true"/> - 对方法级的权限控制
- 1.添加依赖包
cglib-nodep- 2.1_3.jaraspectjweaver.jar aspectjrt.jar - 2.利用<global-method-security>设置需要保护的方法及可以调用的权限
- <global-method-security>
- <protect-pointcut
access= "ROLE_ADMIN,ROLE_USER"expression= "execution(*com.lovo.bo.AccountBo.get*(..))" /> - <protect-pointcut
access= "ROLE_ADMIN"expression= "execution(*com.lovo.bo.AccountBo.create*(..))" /> - </global-method-security>
- 利用注解同样可以实现方法级的保护
- 需要spring-security-core-tiger.jar包
- 启用注解保护
- <global-method-security
secured-annotations= "enabled"/> - @Secured({"ROLE_ADMIN","ROLE_USER"})
- public
void getOneAccount(); - 拥护ROLE_ADMIN或ROLE_USER权限的用户可以调用该方法
- SecurityContext安全上下文
- SecurityContext
securityContext = SecurityContextHolder.getContext(); - SecurityContext中保存着实现了Authentication
接口的对象,如果用户尚未通过 - 认证,那么SecurityContext.getAuthenticaiton()方法就会返回null。
null.注意,如果使用了匿名用户,SecurityContext.getAuthenticaiton()返回的不是 只有在未启用过滤器链的情况下,SecurityContext.getAuthenticaiton()才返回空。 验证管理器 验证管理器用来识别用户的身份。使用命名空间会自动注册一个验证管理器的bean. 是org.springframework.security.providers.ProviderManager类的一个对象。 如果要在其他的bean中要引用这个验证管理器,则给这个验证管理器取一个别名。 "authenticationManager"/><authentication-manager alias= 如果要采用其他的类来完成验证管理器的功能,可以使用以下标签 "abc"<beans:bean id= class="org.springframework.security.providers.dao.DaoAuthenticationProvide r" ><custom-authentication-provider/> </beans:bean> 访问决策管理器 当使用命名空间配置时,默认的AccessDecisionManager实例会自动注册。 默认的策略是使用一个AffirmativeBased作为AccessDecisionManager(访问决策管理器),投票者是RoleVoter 和 - AuthenticatedVote
- <global-method-security
secured-annotations= "enabled"access-decision-manager-ref= "accessDecisionManager"> - </global-method-security>
- 利用访问决策管理器对方法进行保护
- <beans:bean
id= "filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityIntercepto r" autowire= "byType"> "FILTER_SECURITY_INTERCEPTOR"/><custom-filter before= "objectDefinitionSource"<beans:property name= ref= "moduleFilter"/> "accessDecisionManager"<beans:property name= ref= "accessDecisionManager"></beans:property></beans:bean> 向过滤器注入访问决策管理器 不管是MethodSecurityIntercepto r还是FilterSecurityIntercepto r都使用 authenticationManager和accessDecisionManager属性用于验证用户,并且都是通过使用 objectDefinitionSource属性来定义受保护的资源。不同的是过滤器安全拦截器将URL资源与权限关联,而方法安全拦截器将业务方法与权限关联。 objectDefinitionSource属性需要注入的就是 org.springframework.security.intercept.ObjectDefinitionSource这个接口的实现类。 该接口中有一个方法是: throwsConfigAttributeDefinitio n getAttributes(Object object) IllegalArgumentException ; 参数实际类型是org.springframework.security.intercept.web.FilterInvocation 这个方法用于获取保护资源对应的权限信息,返回一个ConfigAttributeDefinitio n对象。 1个列表,安全拦截器就通过调用getAttributes方法来获取ConfigAttributeDefinitio n对象内部维护 ConfigAttributeDefinitio n对象,并将该对象和当前用户拥有的Authentication对象传递给 accessDecisionManager(访问决策管理器) 访问决策管理器在将其传递给具体实现类维护的投票者,这些投票者从ConfigAttributeDefinitio n对象中获取这个存放了访问保护资源需要的权限信息的列表,然后遍历这个列表并与 Authentication对象中GrantedAuthority[]数据中的用户权限信息进行匹配,如果匹配成功,投票者就会投赞成票,否则就投反对票,最后访问决策管理器来统计这些投票决定用户是否能访问该资源。 2个默认实现类用以从配置文件读取权限信息。FilterInvocationDefiniti onSource接口和MethodDefinitionSource接口继承自 ObjectDefinitionSource接口,并提供了 是DefaultFilterInvocationD efinitionSource和 DelegatingMethodDefiniti onSource两个类,如果需要从其他数据来源读取则需要实现 FilterInvocationDefiniti onSource接口和MethodDefinitionSource接口。 自定义的过滤器必须注入 objectDefinitionSource,accessDecisionManager,authenticationManager3个属性。 FilterInvocationDefiniti onSource接口getAttributes实现思路 1.获取客户端访问的url地址。 2.将该url地址和数据库中存储的url地址匹配,找到所有有权访问该地址的权限(角色)名字。 3.把所有的权限名利用ConfigAttributeEditor类封装成ConfigAttributeDefinition对象 - 简单例子:
- public
class MyFilter extendsHibernateDaoSupport implementsFilterInvocationDefiniti onSource,FactoryBean{ - //保存权限信息(能够访问当前资源的角色名)
- private
List<String> newroleNameList = ArrayList<String>(); - public
ConfigAttributeDefinitio throwsn getAttributes(Object object) IllegalArgumentException { - FilterInvocation
fi = (FilterInvocation)object; - String
requeatUrl //获取客户端访问的url地址= fi.getRequestUrl(); - requeatUrl
= //将url地址全部转换成小写requeatUrl.toLowerCase(); - if(requeatUrl.indexOf("?")
!= 1){- //过滤请求参数 - requeatUrl
= 0,requeatUrl.indexOf("?"));requeatUrl.substring( - }
- //在数据库中查找能够访问此url地址的角色
- List<Module>
list this.getHibernateTemplate().find("from= com.lovo.po.Module ,requeatUrl+"%");where url like ?" - if(list.size()
<= 0){ - return
null; - }
- String
s "";= - Module
module 0);= (Module)list.get( - Set<Role>
set = module.getRoleSet(); - roleNameList.clear();
- for(Role
role : set){ - roleNameList.add(role.getDescn());
- s
+= ",";role.getDescn() + - }
- s
= 0,(s.length()s.substring( - 1)); //将所有的角色名(ROLE_开头)拼接为一个字符串。 - ConfigAttributeEditor
editer new= ConfigAttributeEditor(); - editer.setAsText(s);
- return
(ConfigAttributeDefinitio //将包含所有角色名(ROLE_开头)的字符串转换为ConfigAttributeDefinition) editer.getValue(); n对象。 - }
- public
Collection getConfigAttributeDefini tions() { returnCollections.unmodifiableCollection( this.roleNameList);- }
- public
boolean supports(Class clazz) { - return
FilterInvocation. class.isAssignableFrom(clazz); - }
- public
Object throwsgetObject() Exception { - return
this; - }
- public
Class getObjectType() { - return
FilterInvocationDefiniti class;onSource. - }
- public
boolean isSingleton() { - //
TODO Auto-generated method stub - return
true; - }
- }
- 方法保护的原理是通过aop来实现的。
- <aop:config>
- <aop:pointcut
expression= "execution(*com.lovo.bo.face.*.*(..))" id= "me"/> - <aop:advisor
advice-ref= "methodSecurityInterceptor" pointcut-ref= "me"/> - </aop:config>
- 通知是1个实现了MethodSecurityIntercepto
r接口的类 - methodSecurityIntercepto
r是spring中的一个类 - <beans:bean
id= "methodSecurityInterceptor" class="org.springframework.security.intercept.method.aopalliance.MethodSecurityIntercepto r" > "objectDefinitionSource"<beans:property name= ref= "methodFilter"/> "accessDecisionManager"<beans:property name= ref= "accessDecisionManager"></beans:property> "authenticationManager"<beans:property name= ref= "authenticationManager"></beans:property>- </beans:bean>
- accessDecisionManager属性注入访问决策管理器,authenticationManager属性注入验证管理器。
- objectDefinitionSource属性注入1个实现了MethodDefinitionSource接口的类。
- <beans:bean
id= "methodFilter"class="com.lovo.method.MethodFilter"> - <beans:property
name= "hibernateTemplate"ref= "hibernateTemplate"></beans:property> - </beans:bean>
这个类的作用是根据用户调用的方法,找到相应的角色, - public
class MethodFilter extendsHibernateDaoSupport implementsMethodDefinitionSource{ - private
List<String> newroleList = ArrayList<String>(); - public
ConfigAttributeDefinitio n getAttributes(Method method, Class targetClass) { - return
null; - }
- public
ConfigAttributeDefinitio n getAttributes(Object object) - throws
IllegalArgumentException { - ConfigAttributeEditor
editor new= ConfigAttributeEditor(); - String
s "";= - ReflectiveMethodInvocati
on rmi = (ReflectiveMethodInvocati on)object; - String
methodName "."= rmi.getThis().getClass().getName() + + rmi.getMethod().getName(); - System.out.println(methodName);
- List<Module>
list this.getHibernateTemplate().find("from= com.lovo.po.Module ,methodName);where url like ?" - if(list.size()
== 0){ - return
null; - }
- roleList.clear();
- for(int
i= 0;i<list.size();i++){ - Module
module = list.get(i); - Set<Role>
roleSet = module.getRoleSet(); - Iterator<Role>
it = roleSet.iterator(); - while(it.hasNext()){
- Role
role = it.next(); - s
+= ",";role.getDescn() + - roleList.add(role.getDescn());
- }
- }
- s
= 0,(s.length()s.substring( - 1)); - editor.setAsText(s);
- editor.getValue();
- return
(ConfigAttributeDefinitio n) editor.getValue(); - }
- public
Collection getConfigAttributeDefini tions() { - return
roleList; - }
- public
boolean supports(Class clazz) { - return
true; - }
- }
- Spring下的权限框架 spring security总结
- Spring Security权限管理框架
- 非常优秀的权限管理框架 -- Spring Security
- Spring Security 权限说明
- spring security 权限验证
- spring security权限管理
- Spring Security权限管理
- Spring Security权限taglib
- Spring Security 权限控制
- spring Security 权限管理
- spring security权限控制
- 使用spring security 实现权限的验证
- spring security控制权限的方法
- spring security基于方法的权限控制
- Spring安全框架 Spring Security
- Spring安全框架 Spring Security
- Spring security框架原理
- Spring Security 安全框架
- struts2 文件上传
- RMAN命令维护
- 以时间命名文件
- XCode修改公司名和作者名
- JQuery的$.ajax()调用后台方法
- Spring下的权限框架 spring security总结
- 技术工程师-年会(三)
- Javac 的逆袭
- 反编译APK获取java代码与图片,字符串资源,xml文件等资源
- 技术工程师-年会(四)
- WP_WP7开发环境搭建(图文教程)
- LED数码管
- ffmpeg 新老接口问题及对照集锦
- Warning: property 'OtherEntrys' not define mapping field , sure?