這幾天項目中用到了SpringSecurity作登錄安全。因此在這寫一下也許能夠幫助一下其餘人,本身也熟悉一下html
SpringSecurity配置文件以下:java
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="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-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <!-- 這個元素用來在你的應用程序中啓用基於安全的註解 <global-method-security pre-post-annotations="enabled" access-decision-manager-ref="myAccessDecisionManager"/> --> <http pattern="/index.html" security="none" /> <http auto-config="true"> <logout logout-success-url="/app/login" /> <form-login login-page="/app/login" default-target-url="/app/admin" authentication-failure-url="/app/loginfailed" /> <!-- "記住我"功能,採用持久化策略(將用戶的登陸信息存放在數據庫表中) --> <!-- <remember-me data-source-ref="dataSource" /> --> <!-- 增長一個自定義的filter,放在FILTER_SECURITY_INTERCEPTOR以前, 實現用戶、角色、權限、資源的數據庫管理--> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR"/> </http> <!-- 實現了UserDetailsService的Bean --> <authentication-manager alias="myAuthenticationManager"> <authentication-provider user-service-ref="myUserDetailService"> <password-encoder hash="plaintext"> </password-encoder> <!-- <password-encoder ref="passwordEncoder"> <salt-source user-property="username" /> </password-encoder> --> </authentication-provider> </authentication-manager> <!-- 一個自定義的filter,必須包含 authenticationManager, accessDecisionManager, securityMetadataSource 三個屬性。 --> <beans:bean id="myFilter" class="com.yihaomen.common.intercept.MyFilterSecurityInterceptor"> <!-- 用戶擁有的權限 --> <beans:property name="authenticationManager" ref="myAuthenticationManager"></beans:property> <!-- 用戶是否擁有所請求資源的權限 --> <beans:property name="accessDecisionManager" ref="myAccessDecisionManager"></beans:property> <!-- 資源與權限對應關係 --> <beans:property name="securityMetadataSource" ref="mySecurityMetadataSource"></beans:property> </beans:bean> </beans:beans>
全部的實現邏輯便在這個FilterInterceptor之中,主要的實現的是這個Interceptor中的三個屬性,而實現的這三個類:web
Interceptor:spring
package com.yihaomen.common.intercept; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.SecurityMetadataSource; import org.springframework.security.access.intercept.AbstractSecurityInterceptor; import org.springframework.security.access.intercept.InterceptorStatusToken; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { // 與spring-security.xml裏的myFilter的屬性securityMetadataSource對應, // 其餘的兩個組件,已經在AbstractSecurityInterceptor定義 @Autowired private FilterInvocationSecurityMetadataSource securityMetadataSource; public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { FilterInvocation fi = new FilterInvocation(request, response, chain); invoke(fi); } public Class<? extends Object> getSecureObjectClass() { return FilterInvocation.class; } public void invoke(FilterInvocation fi) throws IOException, ServletException { // object爲FilterInvocation對象 // super.beforeInvocation(fi);源碼 // 1.獲取請求資源的權限 // 執行Collection<ConfigAttribute> attributes = // SecurityMetadataSource.getAttributes(object); // 2.是否擁有權限 // this.accessDecisionManager.decide(authenticated, object, attributes); InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.afterInvocation(token, null); } } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.securityMetadataSource; } public void setSecurityMetadataSource( FilterInvocationSecurityMetadataSource securityMetadataSource) { this.securityMetadataSource = securityMetadataSource; } public void destroy() { } public void init(FilterConfig filterconfig) throws ServletException { } }
package com.yihaomen.comm.service; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; import com.yihaomen.common.dao.ResourcesDao; import com.yihaomen.common.domain.SysResource; public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource { @Autowired private ResourcesDao resourcesDao; // resourceMap及爲key-url,value-Collection<ConfigAttribute>,資源權限對應Map private static Map<String, Collection<ConfigAttribute>> resourceMap = null; public MyInvocationSecurityMetadataSourceService(ResourcesDao resourcesDao) { this.resourcesDao = resourcesDao; System.out.println("加載MyInvocationSecurityMetadataSourceService..." + resourcesDao); loadResourceDefine(); } // 加載全部資源與權限的關係 private void loadResourceDefine() { if (resourceMap == null) { resourceMap = new HashMap<String, Collection<ConfigAttribute>>(); List<SysResource> resources = resourcesDao.findAll(); // 加載資源對應的權限 for (SysResource resource : resources) { Collection<ConfigAttribute> auths = resourcesDao .loadRoleByResource(resource.getResource()); System.out.println("權限=" + auths); resourceMap.put(resource.getResource(), auths); } } } //由資源路徑得到權限 //object爲請求的資源路徑 public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { // object是一個URL,被用戶請求的url String requestUrl = ((FilterInvocation) object).getRequestUrl(); System.out.println("requestUrl is " + requestUrl); int firstQuestionMarkIndex = requestUrl.indexOf("?"); //若是請求的資源路徑有?後面的參數,則將?後面的切掉,以避免拒絕訪問 if (firstQuestionMarkIndex != -1) { requestUrl = requestUrl.substring(0, firstQuestionMarkIndex); } if (resourceMap == null) { loadResourceDefine(); } // Iterator<String> ite = resourceMap.keySet().iterator(); //根據資源路徑得到其所需的權限 while (ite.hasNext()) { String resURL = ite.next(); if (resURL.equals(requestUrl)) { return resourceMap.get(resURL); } } return null; } public boolean supports(Class<?> arg0) { // TODO Auto-generated method stub return true; } public Collection<ConfigAttribute> getAllConfigAttributes() { // TODO Auto-generated method stub return null; } }
package com.yihaomen.comm.service; import java.sql.SQLException; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import com.yihaomen.common.dao.UserInfoDao; import com.yihaomen.common.domain.SysUser; /** * 根據用戶名得到其所擁有的權限,返回該用戶的狀態信息。並將其所擁有的權限放入GrantedAuthority中 * @author Administrator * */ public class MyUserDetailService implements UserDetailsService { @Autowired private UserInfoDao userInfoDao; @Autowired private UserCache userCache; public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { System.out.println("username is :" + username); SysUser user = null; try { user = this.userInfoDao.findByName(username); System.out.println(user); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 得到用戶權限 Collection<GrantedAuthority> auths = userInfoDao .loadUserAuthorityByName(username); boolean enables = true; // 帳戶過時否 boolean accountNonExpired = true; // 證書過時否 boolean credentialsNonExpired = true; // 帳戶鎖定否 boolean accountNonLocked = true; // 封裝成spring security的user User userdetail = new User(username, user.getPassword(), enables, accountNonExpired, credentialsNonExpired, accountNonLocked, auths); for (GrantedAuthority s : auths) { s.getAuthority(); } System.out.println(auths); return userdetail; } public UserInfoDao getUserInfoDao() { return userInfoDao; } public void setUserInfoDao(UserInfoDao userInfoDao) { this.userInfoDao = userInfoDao; } //設置用戶緩存功能。 public UserCache getUserCache() { return userCache; } public void setUserCache(UserCache userCache) { this.userCache = userCache; } }
package com.yihaomen.comm.service; import java.util.Collection; import java.util.Iterator; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.access.SecurityConfig; import org.springframework.security.authentication.InsufficientAuthenticationException; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; public class MyAccessDecisionManager implements AccessDecisionManager { public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (configAttributes == null) { return; } //所請求的資源擁有的權限(一個資源對多個權限) Iterator<ConfigAttribute> ite = configAttributes.iterator(); while (ite.hasNext()) { ConfigAttribute ca = ite.next(); //訪問所請求資源所須要的權限 String needRole = ((SecurityConfig) ca).getAttribute(); System.out.println("needRole is " + needRole); // ga 爲用戶所被賦予的權限。 needRole 爲訪問相應的資源應該具備的權限。 for (GrantedAuthority ga : authentication.getAuthorities()) { if (needRole.trim().equals(ga.getAuthority().trim())) { return; } } } //沒有權限 throw new AccessDeniedException("沒有權限訪問!"); } public boolean supports(ConfigAttribute arg0) { // TODO Auto-generated method stub return true; } public boolean supports(Class<?> arg0) { // TODO Auto-generated method stub return true; } }