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; } }