package com.shenzhen.management.util.security;


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;


/**

 *AccessdecisionManager在Spring security中是很重要的。 

 * 

 *在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。  

 *这就是赋予给主体的权限。 GrantedAuthority对象通过AuthenticationManager 

 *保存到 Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。  

 * 

 *Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。  

 *一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。  

 *这个 AccessDecisionManager 被AbstractSecurityInterceptor调用, 

 *它用来作最终访问控制的决定。 这个AccessDecisionManager接口包含三个方法:  

 * 

 void decide(Authentication authentication, Object secureObject, 

    List config) throws AccessDeniedException; 

 boolean supports(ConfigAttribute attribute); 

 boolean supports(Class clazz); 

  

  从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。  

  特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。  

  比如,让我们假设安全对象是一个MethodInvocation。  

  很容易为任何Customer参数查询MethodInvocation, 

  然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。  

  如果访问被拒绝,实现将抛出一个AccessDeniedException异常。 

 

  这个 supports(ConfigAttribute) 方法在启动的时候被 

  AbstractSecurityInterceptor调用,来决定AccessDecisionManager 

  是否可以执行传递ConfigAttribute。  

  supports(Class)方法被安全拦截器实现调用, 

  包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。 

 */ 

public class MyAccessDecisionManager implements AccessDecisionManager {


public void decide( Authentication authentication, Object object, Collection configAttributes)   

 throws AccessDeniedException, InsufficientAuthenticationException{  

   

 if( configAttributes == null ) {  

 

 return ;  

 }  

   

 Iterator iterator = configAttributes.iterator();  

   

 while(iterator.hasNext()){  

    

  ConfigAttribute configAttribute = iterator.next();  

  String needRole = ((SecurityConfig)configAttribute).getAttribute();  

    

  //grantedAuthority 为用户所被赋予的权限。 needRole为访问相应的资源应该具有的权限。  

  for( GrantedAuthority grantedAuthority: authentication.getAuthorities()){  

     

   if(needRole.trim().equals(grantedAuthority.getAuthority().trim())){  

 

    return;  

   }  

     

      }  

    

 }  

   

 throw new AccessDeniedException("");  

   

}  

  

public boolean supports( ConfigAttribute attribute ){  

   

    return true;  

 

}  

  

public boolean supports(Class clazz){  

 

    return true;  

 

}  


}

-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

package com.shenzhen.management.util.security;


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


/**

 * 

 * 该过滤器的主要作用就是通过spring著名的IoC生成securityMetadataSource。 

 * securityMetadataSource相当于本包中自定义的MyInvocationSecurityMetadataSourceService。 

 * 该MyInvocationSecurityMetadataSourceService的作用提从数据库提取权限和资源,装配到HashMap中, 

 * 供Spring Security使用,用于权限校验。 

 * 

 */

public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {


private FilterInvocationSecurityMetadataSource securityMetadataSource;

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {


FilterInvocation filterInvocation = new FilterInvocation(request, response, chain);

invoke(filterInvocation);


}


public Class getSecureObjectClass() {

return FilterInvocation.class;

}


public void invoke(FilterInvocation filterInvocation) throws IOException, ServletException {


InterceptorStatusToken token = super.beforeInvocation(filterInvocation);


try {

filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse());

} finally {

super.afterInvocation(token, null);

}


}


@Override

public SecurityMetadataSource obtainSecurityMetadataSource() {

return this.securityMetadataSource;

}


public void destroy() {


}


public void init(FilterConfig filterconfig) throws ServletException {


}

public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {

return this.securityMetadataSource;

}

public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {

this.securityMetadataSource = securityMetadataSource;

}

}


-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

package com.shenzhen.management.util.security;


import java.util.ArrayList;

import java.util.Collection;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.access.SecurityConfig;

import org.springframework.security.web.FilterInvocation;

import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import org.springframework.security.web.util.AntUrlPathMatcher;

import org.springframework.security.web.util.UrlMatcher;

import com.shenzhen.management.dao.UserDao;


/**

 * 最核心的地方,就是提供某个资源对应的权限定义,即getAttributes方法返回的结果。 此类在初始化时,应该取到所有资源及其对应角色的定义。 

 *  

 */

public class MyInvocationSecurityMetadataSourceService implements

FilterInvocationSecurityMetadataSource {


private UrlMatcher urlMatcher = new AntUrlPathMatcher();


private static Map> resourceMap = null;


public MyInvocationSecurityMetadataSourceService() {

loadResourceDefine();

}


private void loadResourceDefine() {


ApplicationContext context = new ClassPathXmlApplicationContext(

"classpath:applicationContext.xml");

UserDao userDao = (UserDao) context.getBean("userDao");


List securities = userDao.getSecurities();

// 应当是资源为key, 权限为value。 资源通常为url, 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。

resourceMap = new HashMap>();


for (String securitie : securities) {

ConfigAttribute configAttribute = new SecurityConfig(securitie);

List resources = userDao.getResources(securitie);

for (String resource : resources) {

String url = resource;

// 判断资源文件和权限的对应关系,如果已经存在相关的资源url,则要通过该url为key提取出权限集合,将权限增加到权限集合中。

if (resourceMap.containsKey(url)) {

Collection value = resourceMap.get(url);

value.add(configAttribute);

resourceMap.put(url, value);

} else {

Collection configAttributes = new ArrayList();

configAttributes.add(configAttribute);

resourceMap.put(url, configAttributes);

}


}


}


}


@Override

public Collection getAllConfigAttributes() {


return null;


}


// 根据URL,找到相关的权限配置。

@Override

public Collection getAttributes(Object object)

throws IllegalArgumentException {


// object 是一个URL,被用户请求的url。

String url = ((FilterInvocation) object).getRequestUrl();

int firstQuestionMarkIndex = url.indexOf("?");

if (firstQuestionMarkIndex != -1) {

url = url.substring(0, firstQuestionMarkIndex);

}


Iterator ite = resourceMap.keySet().iterator();


while (ite.hasNext()) {

String resURL = ite.next();


if (urlMatcher.pathMatchesUrl(url, resURL)) {


return resourceMap.get(resURL);

}

}


return null;

}


@Override

public boolean supports(Class arg0) {


return true;

}


}



-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

package com.shenzhen.management.util.security;


import java.util.ArrayList;

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.shenzhen.management.dao.UserDao;


public class MyUserDetailsService implements UserDetailsService {


@Autowired

private UserDao userDao;


@Autowired

private UserCache userCache;

/**

*该类的主要作用是为Spring Security提供一个经过用户认证后的UserDetails。 

*该UserDetails包括用户名、密码、是否可用、是否过期等信息。 

*/ 

@Override

public UserDetails loadUserByUsername(String username)

throws UsernameNotFoundException, DataAccessException {


Collection auths = new ArrayList();


// 得到用户的权限

auths = userDao.loadUserAuthoritiesByName(username);


String password = null;


// 取得用户的密码

password = userDao.getPasswordByUsername(username);


return new User(username, password, true, true, true, true, auths);

}


public UserDao getUserDao() {

return userDao;

}



public void setUserDao(UserDao userDao) {

this.userDao = userDao;

}



// 设置用户缓存功能。

public void setUserCache(UserCache userCache) {

this.userCache = userCache;

}


public UserCache getUserCache() {

return this.userCache;

}


}



-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

 xmlns:b="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.0.xsd">  

  

  

   

   

   

   

   

   

   

   

   

 

   filters="none" />    

    

 

   authentication-failure-url="/index.jsp?error=true"  

   default-target-url="/index.jsp" />  

  

   

   

    

   

   

    

    

   

    

    

    

   

   

   

   

 

  class="com.shenzhen.management.util.security.MyFilterSecurityInterceptor">  

 

   ref="authenticationManager"/>  

 

   ref="myAccessDecisionManager"/>  

 

   ref="mySecurityMetadataSource"/>  

   

   

   

  

   

   

   

     

     

     

   

   

  

  

   

 

  class="com.shenzhen.management.util.security.MyAccessDecisionManager">  

     

  

  

   

 

  class="com.shenzhen.management.util.security.MyInvocationSecurityMetadataSourceService">  

    

  

 



-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   

 xmlns:util="http://www.springframework.org/schema/util"  

 xmlns:jee="http://www.springframework.org/schema/jee"   

 xmlns:aop="http://www.springframework.org/schema/aop"  

 xmlns:tx="http://www.springframework.org/schema/tx"   

 xmlns:context="http://www.springframework.org/schema/context"  

 xsi:schemaLocation="http://www.springframework.org/schema/beans  

 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

   http://www.springframework.org/schema/aop   

   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  

   http://www.springframework.org/schema/tx  

   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  

   http://www.springframework.org/schema/jee  

   http://www.springframework.org/schema/jee/spring-jee-3.0.xsd  

   http://www.springframework.org/schema/context  

   http://www.springframework.org/schema/context/spring-context-3.0.xsd  

   http://www.springframework.org/schema/util   

   http://www.springframework.org/schema/util/spring-util-3.0.xsd">  

   

   

 

  class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  

 

   value="classpath:org/springframework/security/messages_zh_CN"/>  

   

  

   

   

  

   

 

  class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />  

  

  

   

 

  class="org.springframework.security.provisioning.JdbcUserDetailsManager">  

   

   

    

   

 

  class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">  

   

    

   

   

   

   

   

   

   

   

 

  class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />  

    

  

   

   

   

   

  

 



-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------

 

    springSecurityFilterChain

    org.springframework.web.filter.DelegatingFilterProxy

 

 

    springSecurityFilterChain

    /*

 



-----------------------------------------------------------默默无闻的分割线-----------------------------------------------------------