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