spring security

spring security 咱们主要是围绕非业务合同项目对spring security的使用进行展开。 咱们总体了解一下这些配置web

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:beans="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
//上面配置的是命名空间

        //线面配置的是路径及路径的访问权限。pattern为路径,secutity为权限,权限为none为都可访问
	<http pattern="/resources/**" security="none" />//这一条是访问资源路径,由于每一个人都须要获取本身的资源路径以后才能够进行权限控制,因此这里的权限为none,同理下面的登陆和获取验证码的路径
	<http pattern="/login" security="none" />
	<http pattern="/" security="none" />
	
	<http pattern="/captchaImage/**" security="none" />
	 


	<http access-decision-manager-ref="accessDecisionManager"
		entry-point-ref="authenticationEntryPoint" authentication-manager-ref="authenticationManager">
		<intercept-url pattern="/**" access="RBAC" />
		<logout logout-url="/logout" success-handler-ref="simpleUrlLogoutSuccessHandler" />
		<custom-filter ref="customUsernamePasswordAuthenticationFilter"  position="FORM_LOGIN_FILTER" />
		<custom-filter ref="concurrentSessionFilter" position="CONCURRENT_SESSION_FILTER" />
		<custom-filter ref="ajaxSessionTimeoutFilter" before="SESSION_MANAGEMENT_FILTER" />
		<!-- <custom-filter ref="systemPathFilter" before="FORM_LOGIN_FILTER" />
		<custom-filter ref="addUserToSessionFilter" after="REMEMBER_ME_FILTER" />
		<custom-filter ref="topMenuBackgroundFilter" before="LAST" /> -->
		<custom-filter ref="addUserToSessionFilter" after="REMEMBER_ME_FILTER" />
		<csrf disabled="true" />

		<!-- 设置x-frame-options,不然ajaxfileupload组件提示x-frame-options错误 -->
		<headers>
			<frame-options policy="
			SAMEORIGIN" />
		</headers>

		<!-- 容许匿名用户 -->
		<!-- <anonymous /> -->

		<!-- 记住密码,默认记住2周 -->
		<!-- <remember-me services-ref="rememberMeServices" key="contract" authentication-success-handler-ref="rememberMeAuthenticationSuccessHandler"/> -->

		<session-management
			session-authentication-strategy-ref="compositeSessionAuthenticationStrategy"
			invalid-session-url="/">
		</session-management>

		<access-denied-handler ref="accessDeniedHandler" />
	</http>


	<!-- <beans:bean id="rememberMeServices"
		class="com.incoshare.base.security.CustomTokenBasedRememberMeServices">
		<beans:constructor-arg value="contract"></beans:constructor-arg>
		<beans:constructor-arg ref="jdbcUserService"></beans:constructor-arg>
	</beans:bean> -->

	<!-- <beans:bean id="sessionRegistry"
		class="com.incoshare.base.security.CustomSpringSessionBackedSessionRegistry">
		<beans:constructor-arg ref="sessionRepository"></beans:constructor-arg>
	</beans:bean> -->
	<beans:bean id="sessionRegistry"
        class="org.springframework.security.core.session.SessionRegistryImpl" />

	<beans:bean id="compositeSessionAuthenticationStrategy"
		class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
		<beans:constructor-arg>
			<beans:list>
				<beans:ref bean="concurrentSessionControlAuthenticationStrategy" />
				<beans:ref bean="sessionFixationProtectionStrategy" />
				<beans:ref bean="registerSessionAuthenticationStrategy" />
			</beans:list>
		</beans:constructor-arg>
	</beans:bean>

	<beans:bean id="concurrentSessionControlAuthenticationStrategy"
		class="com.contract.base.security.CustomConcurrentSessionControlAuthenticationStrategy">
		<beans:constructor-arg ref="sessionRegistry"></beans:constructor-arg>
	</beans:bean>

	<beans:bean id="registerSessionAuthenticationStrategy"
		class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
		<beans:constructor-arg ref="sessionRegistry"></beans:constructor-arg>
	</beans:bean>

	<beans:bean id="sessionFixationProtectionStrategy"
		class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
	</beans:bean>

	<beans:bean id="concurrentSessionFilter"
		class="org.springframework.security.web.session.ConcurrentSessionFilter">
		<beans:constructor-arg ref="sessionRegistry"></beans:constructor-arg>
		<beans:constructor-arg value="/"></beans:constructor-arg>
	</beans:bean>
        
        <--AuthenticationEntryPoint是spring-security的一个起点,在这个起点,收集用户的信息,通常把这个入口设置在登陆页面,LoginUrlAuthenticationEntryPoint为其实现类-->
	<beans:bean id="authenticationEntryPoint"
		class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
		p:useForward="true">
		<beans:constructor-arg value="/login"></beans:constructor-arg>
	</beans:bean>

	<beans:bean id="ajaxSessionTimeoutFilter"
		class="com.contract.base.security.AjaxSessionTimeoutFilter">
	</beans:bean>

	<!-- <beans:bean id="topMenuBackgroundFilter"
		class="com.incoshare.base.security.TopMenuBackgroundFilter">
	</beans:bean> -->


	<beans:bean id="accessDeniedHandler"
		class="com.contract.base.security.CustomAccessDeniedHandlerImpl"
		p:errorPage="/denyAccess" />

	<beans:bean id="simpleUrlLogoutSuccessHandler"
		class="com.contract.base.security.CustomSimpleUrlLogoutSuccessHandler" 
		p:targetUrlParameter="logoutToUrl" />
		<!-- p:redisTemplate-ref="redisTemplate" -->

//这里是一个可否进入的决定管理者,他是经过一个投票中心决定的
	<beans:bean id="accessDecisionManager"
		class="org.springframework.security.access.vote.AffirmativeBased">
		<beans:constructor-arg>
			<beans:list>
				<beans:ref bean="rbacVoter" />
			</beans:list>
		</beans:constructor-arg>
	</beans:bean>
        <--投票机制的实现,实际上是对路径的控制,哪路请求能够访问,哪些不能-->
	<beans:bean id="rbacVoter" class="com.contract.base.security.RbacVoter" />


	<beans:bean id="authenticationFailureHandler"
		class="com.contract.base.security.CustomSimpleUrlAuthenticationFailureHandler"
		p:defaultFailureUrl="/login" p:useForward="true" />

	<beans:bean id="authenticationSuccessHandler"
		class="com.contract.base.security.CustomAuthenticationSuccessHandler"
		p:alwaysUseDefaultTargetUrl="true" />

	<!-- <beans:bean id="rememberMeAuthenticationSuccessHandler"
		class="com.incoshare.base.security.CustomRememberMeAuthenticationSuccessHandler"
		p:alwaysUseDefaultTargetUrl="true" />
 -->

	<beans:bean id="passwordEncoder"
		class="com.contract.base.security.CustomMessageDigestPasswordEncoder">
		<beans:constructor-arg value="md5"></beans:constructor-arg> 
		<beans:constructor-arg value="true"></beans:constructor-arg>
	</beans:bean>

	<beans:bean id="customWebAuthenticationDetailsSource"
		class="com.contract.base.security.CustomWebAuthenticationDetailsSource">
	</beans:bean>

	<beans:bean id="customUsernamePasswordAuthenticationFilter"
		class="com.contract.base.security.CustomUsernamePasswordAuthenticationFilter"
		p:authenticationManager-ref="authenticationManager"
		p:filterProcessesUrl="/doLogin" p:sessionAuthenticationStrategy-ref="compositeSessionAuthenticationStrategy"
		p:authenticationSuccessHandler-ref="authenticationSuccessHandler"
		p:authenticationFailureHandler-ref="authenticationFailureHandler"    
		p:authenticationDetailsSource-ref="customWebAuthenticationDetailsSource">
		<!-- p:rememberMeServices-ref="rememberMeServices" -->
	</beans:bean>

	<beans:bean id="authenticationProvider"
		class="com.contract.base.security.CustomDaoAuthenticationProvider"
		p:userDetailsService-ref="jdbcUserService"
		 p:passwordEncoder-ref="passwordEncoder">
		
	</beans:bean>

	<!-- <beans:bean id="ipAuthenticationProvider"
		class="com.incoshare.base.security.CustomIpDaoAuthenticationProvider"
		p:userDetailsService-ref="ipuserJdbcDaoImpl">
	</beans:bean>

	<beans:bean id="ipuserJdbcDaoImpl"
		class="com.incoshare.base.security.IpuserJdbcDaoImpl"
		p:dataSource-ref="dataSource">
	</beans:bean> -->

	<authentication-manager alias="authenticationManager"
		id="authenticationManager" erase-credentials="false">
		<authentication-provider ref="authenticationProvider">
		</authentication-provider>
		<!-- <authentication-provider ref="ipAuthenticationProvider">
		</authentication-provider> -->
	</authentication-manager>

	<beans:bean id="jdbcUserService"
		class="com.contract.base.security.CustomJdbcDaoImpl"
		p:dataSource-ref="dataSource"
		p:usersByUsernameQuery="SELECT employee_account,employee_password,1 FROM contract_employee WHERE employee_account=?"
		p:authoritiesByUsernameQuery="SELECT ce.employee_account,cer.role_id FROM contract_employee ce,contract_employee_role cer WHERE ce.employee_id=cer.employee_id AND ce.employee_account=?">
	</beans:bean>


	<beans:bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<beans:property name="basename"
			value="classpath:messages/security/messages" />
	</beans:bean>
	<!-- <beans:bean id="localeResolver"
		class="org.springframework.web.servlet.i18n.SessionLocaleResolver" /> -->

</beans:beans>

rbacVoter投票类ajax

//首先这个类要实现AccessDecisionVoter 接口,也是spring-security的默认接口
public class RbacVoter implements AccessDecisionVoter {
        
        //这里注入的是具体某个项目查询权限的业务层实现类/接口
	@Autowired
	private ContractEmployeeService contractEmployeeService;

	// 每一个登陆用户都能访问的url,这些url定义为一个静态数组
	public static String[] shouldPassUrls = {
			"/",//注意这里是/不是/*
			"/index",//访问默认页面
			"/image/**",//访问图片
			
	};
        
//查看一个请求是否为异步请求,
	private boolean isAjax(HttpServletRequest request) {
		return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest"
				.equals(request.getHeader("X-Requested-With").toString()));
	}
//实现的重写方法,该方法返回0则没有权限访问,返回1则能够访问
//这个类的vote方法,基本上是每次强求后台,都须要进入这个方法,这有在spring-security.xml中配置security为none的pattern才不会进入该方法
	public int vote(Authentication authentication, Object object,
			Collection attributes) {
                //这里是一个过滤器序列,并获取当前的请求路径
		FilterInvocation fi = (FilterInvocation) object;
		String url = fi.getRequestUrl();
                //这里是经过spring的身份认证类,获取当前登陆用户的帐号
		String name = authentication.getName();

		// 这里是一些相似业务上比较特殊的路径,能够不用权限和登陆,直接就经过,
		if (url.startsWith("/a/init") || url.startsWith("/a/upload") || url.startsWith("/a/download")) {
			return 1;
		}

                //下面的逻辑比较常规就是经过登陆员工,查询该员工拥有的权限
		ContractEmployee contractEmployee = this.contractEmployeeService.selectByAccount(name);
                //若是目前登陆,则继续执行逻辑。不然直接回复0(即拒绝)
		if (contractEmployee != null) {

			// 对于一些全部用户都应该能访问的url,不作限制,上面静态数组定义的路径
			for (String turl : this.shouldPassUrls) {
                                //这是一个url匹配器,能够识别url通配符,当当前请求路径和静态中的路径匹配时,返回1,这里要注意,静态类中的路径,通常都是带有通配符的,而,上面业务是上直接放行的路径,只能是具体的某个请求路径。
				AntPathRequestMatcher matcher = new AntPathRequestMatcher(turl);
				if (matcher.matches(fi.getHttpRequest())) {
					return 1;
				}
			}
                        //查找该员工所拥有的权限,遍历
			for (ContractResource p : this.contractEmployeeService.selectResources(contractEmployee.getEmployeeId())) {
				if (p.getResourceUrl() == null) {
					continue;
				}
				String[] urls = p.getResourceUrl().split(",");
				for (String permissionUrl : urls) {
					if (StringUtils.isNotBlank(permissionUrl)) {
                                                //现有路径一样匹配请求路径,匹配则返回1
						AntPathRequestMatcher matcher = new AntPathRequestMatcher(
								permissionUrl);
                            
						if (matcher.matches(fi.getHttpRequest())) {
							return 1;
						}
					}
				}

			}

		}

		return 0;
	}

	public boolean supports(ConfigAttribute attribute) {
		// TODO Auto-generated method stub
		return true;
	}

	public boolean supports(Class clazz) {
		// TODO Auto-generated method stub
		return true;
	}

}
相关文章
相关标签/搜索