`
ywlqi
  • 浏览: 69347 次
社区版块
存档分类
最新评论

Spring中集成Acegi 2.x安全框架——基于数据库配置

阅读更多
一、数据库结构
采用常用的用户——角色——资源结构



二、在web.xml的配置
	<!-- Acegi filter -->
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
	    <filter-name>springSecurityFilterChain</filter-name>
	    <url-pattern>/*</url-pattern>
	</filter-mapping>
	


三、在applicationContext-security.xml中的配置
<b:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:b="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd"
	default-autowire="byName" default-lazy-init="true">

	<b:bean id="springSecurityFilterChain"
		class="org.springframework.security.util.FilterChainProxy">
		<filter-chain-map path-type="ant">
			<filter-chain pattern="/**"
				filters="httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor" />
		</filter-chain-map>
	</b:bean>
	
	<!-- 这样 SecurityContext可以在web请求的开始阶段通过 SecurityContextHolder建立,然后 SecurityContext的任何修改都会在web请求结束的时候(为下一个web请求做准备)复制到 HttpSession中  -->
	<b:bean id="httpSessionContextIntegrationFilter"
		class="org.springframework.security.context.HttpSessionContextIntegrationFilter" />

	<!-- 用户名、密码验证 -->
	<b:bean id="authenticationProcessingFilter"
		class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
		<b:property name="authenticationManager"
			ref="authenticationManager" />
		<b:property name="authenticationFailureUrl"
			value="/login.jsp?login_error=1" />
		<b:property name="defaultTargetUrl" value="/index.jsp" />
		<b:property name="filterProcessesUrl"
			value="/j_spring_security_check" />
	</b:bean>

	<!-- 用来捕捉 Spring Security异常,这样,可能返回一个HTTP错误响应,或者执行一个对应的 AuthenticationEntryPoint。 -->
	<b:bean id="exceptionTranslationFilter"
		class="org.springframework.security.ui.ExceptionTranslationFilter">
		<b:property name="authenticationEntryPoint"
			ref="authenticationProcessingFilterEntryPoint" />
		<b:property name="accessDeniedHandler">
			<b:bean
				class="org.springframework.security.ui.AccessDeniedHandlerImpl">
				<b:property name="errorPage" value="/accessDenied.jsp" />
			</b:bean>
		</b:property>
	</b:bean>

	<!-- 保护web URI -->
	<b:bean id="filterInvocationInterceptor"
		class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
		<b:property name="authenticationManager"
			ref="authenticationManager" />
		<b:property name="accessDecisionManager"
			ref="accessDecisionManager" />
		<b:property name="objectDefinitionSource"
			ref="secureResourceFilter" />
	</b:bean>

	<!-- 认证管理器 -->
	<b:bean id="authenticationManager"
		class="org.springframework.security.providers.ProviderManager">
		<b:property name="providers">
			<b:list>
				<b:ref bean="daoAuthenticationProvider" />
			</b:list>
		</b:property>
		<b:property name="sessionController" ref="concurrentSessionController" />
	</b:bean>

	<!-- 并发访问控制 -->
	<b:bean id="concurrentSessionController"
		class="org.springframework.security.concurrent.ConcurrentSessionControllerImpl">
		<b:property name="maximumSessions" value="1" />
		<b:property name="exceptionIfMaximumExceeded" value="true"></b:property>
		<b:property name="sessionRegistry">
			<b:bean class="org.springframework.security.concurrent.SessionRegistryImpl"/>
		</b:property>
	</b:bean>

	<!-- dao身份认证提供者,从数据库中获取用户信息,包括用户名和密码 -->
	<b:bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
		<b:property name="userDetailsService" ref="userDetailsService" />
	</b:bean>

	<!-- 
	访问决策管理器 
		 Acegi提供三种投票通过策略的实现:
         1、AffirmativeBased(至少一个投票者同意方可通过)
         2、ConsensusBased(多数投票者同意方可通过)
         3、UnanimousBased(所有投票者同意方可通过)
	-->
	<b:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
		<b:property name="allowIfAllAbstainDecisions" value="false" /><!-- 设定是否允许 “没人反对就通过” 的投票策略 --> 
		<b:property name="decisionVoters"><!-- 投票者 --> 
			<b:list>
				<b:bean class="org.springframework.security.vote.RoleVoter" />
			</b:list>
		</b:property>
	</b:bean>


	<!-- 自定义的FilterInvocationDefinitionSource,在Spring Security需要对请求页面检测权限的时候调用 -->
	<b:bean id="secureResourceFilter"
		class="com.ywlqi.common.components.acegi.filter.MySecureResourceFilter">
		<b:property name="resourceService" ref="resourceService" />
		<b:property name="protectAllResource" value="true"></b:property>
		<b:property name="useAntPath" value="true"></b:property>
	</b:bean>

	<!-- 如果用户请求受保护的HTTP请求,但是他们没有认证时被调用 -->
	<b:bean id="authenticationProcessingFilterEntryPoint"
		class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
		<b:property name="loginFormUrl" value="/login.jsp" />
		<b:property name="forceHttps" value="false" />
	</b:bean>
	
	<b:bean id="loggerListener"
		class="org.springframework.security.event.authentication.LoggerListener" />

	<b:bean id="userDetailsService"
		class="com.ywlqi.common.components.acegi.service.UserDetailServiceImpl">
		<b:property name="userService" ref="userService" />
	</b:bean>

	<!-- 自定义的用户、角色、资源管理 -->
	<b:bean id="userService" class="com.ywlqi.common.components.acegi.service.UserService" parent="baseService"/>

	<b:bean id="resourceService" class="com.ywlqi.common.components.acegi.service.ResourceService" parent="baseService" />

	<b:bean id="roleService" class="com.ywlqi.common.components.acegi.service.RoleService" parent="baseService" />
</b:beans>


三、userDetailsService 代码
public class UserDetailServiceImpl implements UserDetailsService{

	private UserService userService;
	public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
		// TODO Auto-generated method stub
		User user = userService.getUserByName(userName);
		if (user == null)
			throw new UsernameNotFoundException(userName + " not found");

		List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority>();

		Set<Role> roles = user.getRoles();

		for (Role role : roles) {
			authsList.add(new GrantedAuthorityImpl(role.getName()));
		}

		org.springframework.security.userdetails.User userdetail = new org.springframework.security.userdetails.User(
				user.getName(), user.getPasswd(), user.isEnabled(), true, true, true, authsList
						.toArray(new GrantedAuthority[0]));

		return userdetail;
	}
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
}


四、MySecureResourceFilter 代码
	public ConfigAttributeDefinition getAttributes(Object filter)
			throws IllegalArgumentException {
		// TODO Auto-generated method stub
		FilterInvocation filterInvocation = (FilterInvocation) filter;

		String url = filterInvocation.getRequestUrl();
		url = preDealUrl(url, isUseAntPath(),
				isConvertUrlToLowercaseBeforeComparison());

		List<Resource> resourceList = resourceService.getResourcesByType("URL");

		Set<Role> authorities = new HashSet<Role>();

		for (Iterator iterator = resourceList.iterator(); iterator.hasNext();) {
			Resource resource = (Resource) iterator.next();
			if (isResourceMatch(isUseAntPath(), url, resource.getResString())) {
				CollectionUtils.addAll(authorities, resource.getRoles().iterator());
			}
		}
		ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
		StringBuffer rolesList = new StringBuffer();
		for (Role role : authorities) {
			rolesList.append(role.getName());
			rolesList.append(",");
		}

		if (rolesList.length() > 0)
			rolesList.replace(rolesList.length() - 1, rolesList.length() + 1, "");

		configAttrEditor.setAsText(rolesList.toString());
		return (ConfigAttributeDefinition) configAttrEditor.getValue();

	}


到这里为止,基于数据库的acegi配置就完成了,在配置的过程中我有些疑问,希望能得到高手的解答:

1、
<authentication-manager alias="authenticationManager" />

这个标签究竟应该怎么使用?貌似是定义认证管理器的,但不知道在哪自定义认证提供者
2、
<http auto-config="true" lowercase-comparisons="true"
		path-type="ant" access-decision-manager-ref="accessDecisionManager"
		access-denied-page="/403.jsp" >
		<concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="true" />
		<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp" default-target-url="/index.jsp" />
		<logout logout-success-url="/login.jsp" />
	</http>

定义这个标签后,貌似
<b:bean id="springSecurityFilterChain"
		class="org.springframework.security.util.FilterChainProxy">
		<filter-chain-map path-type="ant">
			<filter-chain pattern="/**"
				filters="httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor" />
		</filter-chain-map>
	</b:bean>

就不起作用了,debug显示加载了默认的Filter
	<b:bean id="filterInvocationInterceptor"
		class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
		<b:property name="authenticationManager" ref="authenticationManager" />
		<b:property name="accessDecisionManager" ref="accessDecisionManager" />
		<b:property name="objectDefinitionSource" ref="secureResourceFilter" />
	</b:bean>
的配置也不起作用了,同样是加载了默认的配置
分享到:
评论
10 楼 man1900 2009-01-09  
看我的实现配置
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:b="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
              http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">	
    <http auto-config="true" lowercase-comparisons="true">
        <intercept-url pattern="/login*" filters="none"/>
        <intercept-url pattern="/images/**" filters="none"/>
        <intercept-url pattern="/styles/**" filters="none"/>
        <intercept-url pattern="/js/**" filters="none"/>
        <intercept-url pattern="/403*" filters="none"/>
        <intercept-url pattern="/404*" filters="none"/>
        <intercept-url pattern="/500*" filters="none"/>
        <intercept-url pattern="/dwr*" filters="none"/>
        <form-login default-target-url="/admin/main.html" login-page="/login.html" authentication-failure-url="/login.html?error=true" login-processing-url="/j_security_check" />

         <logout logout-url="/j_logout" logout-success-url="/login.html"/>
         
    </http>
    
    <authentication-provider user-service-ref="appUserDAO"/>

    <b:bean id="filterInvocationInterceptor" class="com.cb.core.security.FilterSecurityInterceptor">
		<custom-filter after="FILTER_SECURITY_INTERCEPTOR"/>
		<b:property name="definitionSource" ref="definitionSource"/>
	</b:bean>
	
	<b:bean id="roleMappingProvider" class="com.cb.core.security.RoleMappingProviderImpl">
	    <b:property name="appRoleDAO" ref="appRoleDAO" />
	</b:bean>

	<b:bean id="definitionSource" class="com.cb.core.security.FilterInvocationDefinitionSourceImpl">
		<b:property name="roleMappingProvider" ref="roleMappingProvider" />
	</b:bean>

</b:beans>
9 楼 ywlqi 2009-01-04  
liqiuxi 写道

man1900 写道
这个是acegi 1.0的实现方式,新的2.0,有更简单的实现。他的标题是2.X呀,正向学习,唉...到低这个是不是更简单的实现嘛


我也看了2.0的例子,但就如我blog里的问题一样,按照新的配置方式,我不知道如何实现我需要的自定义配置,这点希望大虾们不吝赐教
8 楼 ywlqi 2009-01-04  
caoyangx 写道

springside论坛中有些人也这么做,既然这么做,为什么还要用2,即使没有问题,那么这与acegi又有什么区别? spring的security2就是配置简单为亮点,你这么搞不如直接用acegi1.x。 这属于自欺欺人,并没有体会到acegi2带给我们的方便。

因为我自身水平问题,可能我真的没体会到acegi2如何更方便,现在我也没时间更仔细的研究,希望各位大侠能给出最优配置。

另外说明一下,虽然配置方式跟1.x的差不多,但我是根据2的说明文档配置的,至于是不是文档没有及时更新就不得而知了。

7 楼 caoyangx 2008-12-31  
springside论坛中有些人也这么做,既然这么做,为什么还要用2,即使没有问题,那么这与acegi又有什么区别?
spring的security2就是配置简单为亮点,你这么搞不如直接用acegi1.x。
这属于自欺欺人,并没有体会到acegi2带给我们的方便。

6 楼 liqiuxi 2008-12-30  
man1900 写道
这个是acegi 1.0的实现方式,新的2.0,有更简单的实现。

他的标题是2.X呀,正向学习,唉...到低这个是不是更简单的实现嘛
5 楼 man1900 2008-12-30  
这个是acegi 1.0的实现方式,新的2.0,有更简单的实现。
4 楼 ywlqi 2008-10-24  
刚刚没看清楚,对链接的管理也是基于数据库的,即我例子中的资源表
3 楼 ywlqi 2008-10-24  
andy54321 写道

请问:这样的集成的话,可以实现在通过页面进行各访问链接的配置吗;就是说:提供队链接的访问控制的编辑页面,为其指定不同的权限;好像你所说的基于数据库配置只是用户信息来自数据库,而对链接的管理还是处于配置文件中

权限分配自己实现就可以了,对权限表的增删改查,很简单吧
2 楼 andy54321 2008-10-20  
请问:
这样的集成的话,可以实现在通过页面进行各访问链接的配置吗;
就是说:提供队链接的访问控制的编辑页面,为其指定不同的权限;
好像你所说的基于数据库配置只是用户信息来自数据库,而对链接的管理还是处于配置文件中
1 楼 onlydo 2008-10-10  
凄惨,我碰到了一样的问题。

相关推荐

Global site tag (gtag.js) - Google Analytics