參考文檔: http://wenku.baidu.com/view/4ec7e324ccbff121dd368364.html
在spring security3中使用自己定義的資料結構來實現使用權限設定。
- 資料庫
- 使用者表
- 角色表
- action表,即資源表
- 角色-使用者關聯表
- actiion-角色關聯表
- 配置過程
- web.xml中加入過濾器
<!-- 配置spiring security --><br /> <filter><br /> <filter-name>springSecurityFilterChain</filter-name><br /> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><br /> </filter><br /> <filter-mapping><br /> <filter-name>springSecurityFilterChain</filter-name><br /> <url-pattern>/*</url-pattern><br /> </filter-mapping><br /><!-- 配置spiring security結束 -->
- 在applicationContext.xml中import spring security部分的配置
<import resource="security3.0_JPA.xml"/>
- 配置import resource="security3.0_JPA.xml
<?xml version="1.0" encoding="UTF-8"?><br /><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</p><p>http://www.springframework.org/schema/beans/spring-beans-3.0.xsd</p><p>http://www.springframework.org/schema/security</p><p> http://www.springframework.org/schema/security/spring-security-3.0.xsd"><br /> <http auto-config="true" access-denied-page="/jsp/accessDenied.jsp"><br /> <intercept-url pattern="/css/**" filters="none" /><br /> <intercept-url pattern="/images/**" filters="none" /><br /> <intercept-url pattern="/js/**" filters="none" /><br /> <!-- 增加一個filter,這點與Acegi是不一樣的,不能修改預設的filter了,<br /> 這個filter位於FILTER_SECURITY_INTERCEPTOR之前 --><br /> <custom-filter ref="myFilter" before="FILTER_SECURITY_INTERCEPTOR" /><br /> </http><br /> <!-- 一個自訂的filter,必須包含authenticationManager,accessDecisionManager,securityMetadataSource三個屬性,<br /> 我們的所有控制將在這三個類中實現,解釋詳見具體配置 --><br /> <beans:bean id="myFilter" class="com.softvan.spring.security.FilterSecurityInterceptor"><br /> <beans:property name="authenticationManager" ref="MyAuthenticationManager" /><br /> <!-- 訪問決策器,決定某個使用者具有的角色,是否有足夠的許可權去訪問某個資源 --><br /> <beans:property name="accessDecisionManager" ref="AccessDecisionManager" /><br /> <beans:property name="securityMetadataSource" ref="MySecurityMetadataSource" /><br /> </beans:bean><br /> <!-- 資源來源資料定義,將所有的資源和許可權對應關係建立起來,即定義某一資源可以被哪些角色訪問 --><br /> <beans:bean id="MySecurityMetadataSource" init-method="loadResourceDefine" class="com.softvan.spring.security.InvocationSecurityMetadataSourceService"><br /> <beans:property name="roleService" ref="RoleService" /><br /> <beans:property name="actionService" ref="ActionService" /><br /> </beans:bean></p><p> <!-- 驗證配置 , 認證管理器,實現使用者認證的入口,主要實現UserDetailsService介面即可 --><br /> <authentication-manager alias="MyAuthenticationManager"><br /> <authentication-provider user-service-ref="UserDetailService"><br /> <!--<br /> <s:password-encoder hash="sha" /><br /> --><br /> </authentication-provider><br /> </authentication-manager><br /></beans:beans>
- 相關java代碼
- AccessDecisionManager.java
/**<br /> *<br /> */<br />package com.softvan.spring.security;<br />import org.apache.log4j.Logger;<br />/**<br /> * @author 徐澤宇(roamer)<br /> *<br /> * 2010-7-4<br /> */<br />import java.util.Collection;<br />import java.util.Iterator;<br />import org.springframework.security.access.AccessDeniedException;<br />import org.springframework.security.access.ConfigAttribute;<br />import org.springframework.security.access.SecurityConfig;<br />import org.springframework.security.authentication.InsufficientAuthenticationException;<br />import org.springframework.security.core.Authentication;<br />import org.springframework.security.core.GrantedAuthority;<br />import org.springframework.stereotype.Service;<br />@Service("AccessDecisionManager")<br />public class AccessDecisionManager implements org.springframework.security.access.AccessDecisionManager {<br />/**<br /> * Logger for this class<br /> */<br />private static final Logger logger = Logger.getLogger(AccessDecisionManager.class);<br />// In this method, need to compare authentication with configAttributes.<br />// 1, A object is a URL, a filter was find permission configuration by this<br />// URL, and pass to here.<br />// 2, Check authentication has attribute in permission configuration<br />// (configAttributes)<br />// 3, If not match corresponding authentication, throw a<br />// AccessDeniedException.<br />public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {<br />if (logger.isDebugEnabled()) {<br />logger.debug("decide(Authentication, Object, Collection<ConfigAttribute>) - start"); //$NON-NLS-1$<br />}<br />if (configAttributes == null) {<br />if (logger.isDebugEnabled()) {<br />logger.debug("decide(Authentication, Object, Collection<ConfigAttribute>) - end"); //$NON-NLS-1$<br />}<br />return;<br />}<br />if (logger.isDebugEnabled()){<br />logger.debug("正在訪問的url是:"+object.toString());<br />}<br />Iterator<ConfigAttribute> ite = configAttributes.iterator();<br />while (ite.hasNext()) {<br />ConfigAttribute ca = ite.next();<br />logger.debug("needRole is:"+ca.getAttribute());<br />String needRole = ((SecurityConfig) ca).getAttribute();<br />for (GrantedAuthority ga : authentication.getAuthorities()) {<br />logger.debug("/t授權資訊是:"+ga.getAuthority());<br />if (needRole.equals(ga.getAuthority())) { // ga is user's role.<br />if (logger.isDebugEnabled()) {<br />logger.debug("判斷到,needRole 是"+needRole+",使用者的角色是:"+ga.getAuthority()+",授權資料相匹配");<br />logger.debug("decide(Authentication, Object, Collection<ConfigAttribute>) - end"); //$NON-NLS-1$<br />}<br />return;<br />}<br />}<br />}<br />throw new AccessDeniedException("沒有許可權");<br />}<br />public boolean supports(ConfigAttribute attribute) {<br />// TODO Auto-generated method stub<br />return true;<br />}<br />public boolean supports(Class<?> clazz) {<br />return true;<br />}<br />}
- FilterSecurityInterceptor.java
/**<br /> *<br /> */<br />package com.softvan.spring.security;<br />import org.apache.log4j.Logger;<br />/**<br /> * @author 徐澤宇(roamer)<br /> *<br /> * 2010-7-4<br /> */<br />import java.io.IOException;<br />import javax.servlet.Filter;<br />import javax.servlet.FilterChain;<br />import javax.servlet.FilterConfig;<br />import javax.servlet.ServletException;<br />import javax.servlet.ServletRequest;<br />import javax.servlet.ServletResponse;<br />import org.springframework.security.access.SecurityMetadataSource;<br />import org.springframework.security.access.intercept.AbstractSecurityInterceptor;<br />import org.springframework.security.access.intercept.InterceptorStatusToken;<br />import org.springframework.security.web.FilterInvocation;<br />import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;<br />public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {<br />/**<br /> * Logger for this class<br /> */<br />private static final Logger logger = Logger.getLogger(FilterSecurityInterceptor.class);<br />private FilterInvocationSecurityMetadataSource securityMetadataSource;<br />public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {<br />if (logger.isDebugEnabled()) {<br />logger.debug("doFilter(ServletRequest, ServletResponse, FilterChain) - start"); //$NON-NLS-1$<br />}<br />FilterInvocation fi = new FilterInvocation(request, response, chain);<br />invoke(fi);<br />if (logger.isDebugEnabled()) {<br />logger.debug("doFilter(ServletRequest, ServletResponse, FilterChain) - end"); //$NON-NLS-1$<br />}<br />}<br />public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {<br />return this.securityMetadataSource;<br />}<br />public Class<? extends Object> getSecureObjectClass() {<br />return FilterInvocation.class;<br />}<br />public void invoke(FilterInvocation fi) throws IOException, ServletException {<br />InterceptorStatusToken token = super.beforeInvocation(fi);<br />try {<br />fi.getChain().doFilter(fi.getRequest(), fi.getResponse());<br />} finally {<br />super.afterInvocation(token, null);<br />}<br />}<br />@Override<br />public SecurityMetadataSource obtainSecurityMetadataSource() {<br />return this.securityMetadataSource;<br />}<br />public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {<br />this.securityMetadataSource = securityMetadataSource;<br />}<br />public void destroy() {<br />// TODO Auto-generated method stub<br />}<br />public void init(FilterConfig filterconfig) throws ServletException {<br />// TODO Auto-generated method stub<br />}<br />}
- InvocationSecurityMetadataSourceService.java
/**<br /> *<br /> */<br />package com.softvan.spring.security;<br />import java.util.ArrayList;<br />import java.util.Collection;<br />import java.util.HashMap;<br />import java.util.Iterator;<br />import java.util.List;<br />import java.util.Map;<br />import org.apache.log4j.Logger;<br />import org.springframework.security.access.ConfigAttribute;<br />import org.springframework.security.access.SecurityConfig;<br />import org.springframework.security.web.FilterInvocation;<br />import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;<br />import org.springframework.security.web.util.AntUrlPathMatcher;<br />import org.springframework.security.web.util.UrlMatcher;<br />import org.springframework.stereotype.Service;<br />import com.alcor.acl.domain.TAction;<br />import com.alcor.acl.domain.TRole;<br />import com.alcor.acl.service.ActionService;<br />import com.alcor.acl.service.RoleService;<br />/*<br /> *<br /> * 最核心的地方,就是提供某個資源對應的許可權定義,即getAttributes方法返回的結果。<br /> * 注意,我例子中使用的是AntUrlPathMatcher這個path matcher來檢查URL是否與資源定義匹配,<br /> * 事實上你還要用正則的方式來匹配,或者自己實現一個matcher。<br /> *<br /> * 此類在初始化時,應該取到所有資源及其對應角色的定義<br /> *<br /> * 說明:對於方法的spring注入,只能在方法和成員變數裡注入,<br /> * 如果一個類要進行執行個體化的時候,不能注入對象和操作對象,<br /> * 所以在建構函式裡不能進行操作注入的資料。<br /> */<br />@Service("InvocationSecurityMetadataSourceService")<br />public class InvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {<br />/**<br /> * Logger for this class<br /> */<br />private static final Logger logger = Logger.getLogger(InvocationSecurityMetadataSourceService.class);</p><p>private RoleService roleService ;<br />private ActionService actionService; </p><p>private UrlMatcher urlMatcher = new AntUrlPathMatcher();<br />private static Map<String, Collection<ConfigAttribute>> resourceMap = null;<br />public void loadResourceDefine()throws Exception {<br />this.resourceMap = new HashMap<String, Collection<ConfigAttribute>>();</p><p>//通過資料庫中的資訊設定,resouce和role<br />for (TRole item:this.roleService.getAllRoles()){<br />Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();<br />ConfigAttribute ca = new SecurityConfig(item.getRoleName());<br />atts.add(ca);<br />List<TAction> tActionList = actionService.findByRoleID(item.getRoleId());<br />//把資源放入到spring security的resouceMap中<br />for(TAction tAction:tActionList){<br />logger.debug("獲得角色:["+item.getRoleName()+"]擁有的acton有:"+tAction.getActionUrl());<br />this.resourceMap.put(tAction.getActionUrl(), atts);<br />}<br />}</p><p>/*//通過寫入程式碼設定,resouce和role<br />resourceMap = new HashMap<String, Collection<ConfigAttribute>>();<br />Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();<br />ConfigAttribute ca = new SecurityConfig("admin");<br />atts.add(ca);<br />resourceMap.put("/jsp/admin.jsp", atts);<br />resourceMap.put("/swf/zara.html", atts);*/ </p><p>}<br />// According to a URL, Find out permission configuration of this URL.<br />public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {<br />if (logger.isDebugEnabled()) {<br />logger.debug("getAttributes(Object) - start"); //$NON-NLS-1$<br />}<br />// guess object is a URL.<br />String url = ((FilterInvocation) object).getRequestUrl();<br />Iterator<String> ite = resourceMap.keySet().iterator();<br />while (ite.hasNext()) {<br />String resURL = ite.next();<br />if (urlMatcher.pathMatchesUrl(url, resURL)) {<br />Collection<ConfigAttribute> returnCollection = resourceMap.get(resURL);<br />if (logger.isDebugEnabled()) {<br />logger.debug("getAttributes(Object) - end"); //$NON-NLS-1$<br />}<br />return returnCollection;<br />}<br />}<br />if (logger.isDebugEnabled()) {<br />logger.debug("getAttributes(Object) - end"); //$NON-NLS-1$<br />}<br />return null;<br />}<br />public boolean supports(Class<?> clazz) {<br />return true;<br />}<br />public Collection<ConfigAttribute> getAllConfigAttributes() {<br />return null;<br />}<br />public RoleService getRoleService() {<br />return roleService;<br />}<br />public void setRoleService(RoleService roleService) {<br />this.roleService = roleService;<br />}<br />public ActionService getActionService() {<br />return actionService;<br />}<br />public void setActionService(ActionService actionService) {<br />this.actionService = actionService;<br />}<br />}
- UserDetailService.java
/**<br /> *<br /> */<br />package com.softvan.spring.security;<br />import java.util.ArrayList;<br />import java.util.Collection;<br />import java.util.Set;<br />import javax.inject.Inject;<br />import org.apache.log4j.Logger;<br />import org.springframework.dao.DataAccessException;<br />import org.springframework.security.core.GrantedAuthority;<br />import org.springframework.security.core.authority.GrantedAuthorityImpl;<br />import org.springframework.security.core.userdetails.User;<br />import org.springframework.security.core.userdetails.UserDetails;<br />import org.springframework.security.core.userdetails.UserDetailsService;<br />import org.springframework.security.core.userdetails.UsernameNotFoundException;<br />import org.springframework.stereotype.Service;<br />import com.alcor.acl.domain.TRole;<br />import com.alcor.acl.domain.TUser;<br />@Service("UserDetailService")<br />public class UserDetailService implements UserDetailsService {<br />/**<br /> * Logger for this class<br /> */<br />private static final Logger logger = Logger.getLogger(UserDetailService.class);<br />@Inject<br />com.alcor.acl.component.User user ; </p><p>public UserDetails loadUserByUsername(String username)throws UsernameNotFoundException, DataAccessException {<br />if (logger.isDebugEnabled()) {<br />logger.debug("loadUserByUsername(String) - start"); //$NON-NLS-1$<br />}</p><p>Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>();</p><p>String password=null;<br />//取得使用者的密碼<br />TUser tUser = user.getUserByName(username);<br />if (tUser ==null){<br />String message = "使用者"+username+"不存在";<br />logger.error(message);<br />throw new UsernameNotFoundException(message);<br />}<br />password=user.getUserByName(username).getPassword();</p><p>//獲得使用者的角色<br />Set<TRole> tRoles =tUser.getTRoles();<br />for(TRole item : tRoles){<br />GrantedAuthorityImpl grantedAuthorityImpl = new GrantedAuthorityImpl(item.getRoleName());<br />if (logger.isDebugEnabled()){<br />logger.debug("使用者:["+tUser.getName()+"]擁有角色:["+item.getRoleName()+"],即spring security中的access");<br />}<br />auths.add(grantedAuthorityImpl);<br />}</p><p> User user = new User(username,password, true, true, true, true, auths);</p><p>if (logger.isDebugEnabled()) {<br />logger.debug("loadUserByUsername(String) - end"); //$NON-NLS-1$<br />}<br /> return user;<br />}<br />}<br />