Spring Security教程(11)---- 使用数据库来管理资源

x33g5p2x  于2021-12-18 转载在 其他  
字(5.8k)|赞(0)|评价(0)|浏览(229)

这个可以说是SpringSecurity最核心的东西,在项目中资源很多肯定不能一一配置到配置文件中,所以用数据库来管理资源是必然的。这个也很容易实现。表结构已经在之前都创建过了。

首先我们要来从数据库中获取到资源与权限的对应列表,这个在dao层实现即可需要获取到url地址和AUTH_**这种权限标识,注意:不是权限ID和资源ID。

public List<Map<String,String>> getURLResourceMapping(){
		String sql = "SELECT S3.RESOURCE_PATH,S2.AUTHORITY_MARK FROM SYS_AUTHORITIES_RESOURCES S1 "+
				"JOIN SYS_AUTHORITIES S2 ON S1.AUTHORITY_ID = S2.AUTHORITY_ID "+
				"JOIN SYS_RESOURCES S3 ON S1.RESOURCE_ID = S3.RESOURCE_ID S3.RESOURCE_TYPE='URL' ORDER BY S3.PRIORITY DESC";
		
		List<Map<String,String>> list = new ArrayList<Map<String,String>>();
		
		Query query = this.entityManager.createNativeQuery(sql);
		List<Object[]> result = query.getResultList();
		Iterator<Object[]> it = result.iterator();
		
		while(it.hasNext()){
			Object[] o = it.next();
			Map<String,String> map = new HashMap<String,String>();
			map.put("resourcePath", (String)o[0]);
			map.put("authorityMark", (String)o[1]);
			list.add(map);
		}
		
		return list;
	}

创建SecurityMetadataSource供过滤器使用,SecurityMetadataSource需要实现FilterInvocationSecurityMetadataSource

public class URLFilterInvocationSecurityMetadataSource implements
		FilterInvocationSecurityMetadataSource,InitializingBean {

	protected final Log logger = LogFactory.getLog(getClass());
	
	private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections.emptyList();
	//权限集合
	private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;
	
	@Autowired
	private SysResourceRepository sysResourceRepository;
	
	/* (non-Javadoc)
	 * @see org.springframework.security.access.SecurityMetadataSource#getAttributes(java.lang.Object)
	 */
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object)
			throws IllegalArgumentException {
		final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        
        Collection<ConfigAttribute> attrs = NULL_CONFIG_ATTRIBUTE;
        
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
            if (entry.getKey().matches(request)) {
            	attrs =  entry.getValue();
            	break;
            }
        }
        logger.info("URL资源:"+request.getRequestURI()+ " -> " + attrs);
        return attrs;
	}

	/* (non-Javadoc)
	 * @see org.springframework.security.access.SecurityMetadataSource#getAllConfigAttributes()
	 */
	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();

        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
            allAttributes.addAll(entry.getValue());
        }

        return allAttributes;
	}

	/* (non-Javadoc)
	 * @see org.springframework.security.access.SecurityMetadataSource#supports(java.lang.Class)
	 */
	@Override
	public boolean supports(Class<?> clazz) {
		return FilterInvocation.class.isAssignableFrom(clazz);
	}
	
	private Map<String,String> loadResuorce(){
		Map<String,String> map = new LinkedHashMap<String,String>();
		
		List<Map<String,String>> list = this.sysResourceRepository.getURLResourceMapping();
		Iterator<Map<String,String>> it = list.iterator();
		while(it.hasNext()){
			Map<String,String> rs = it.next();
			String resourcePath = rs.get("resourcePath");
			String authorityMark = rs.get("authorityMark");
			
			if(map.containsKey(resourcePath)){
				String mark = map.get("resourcePath");
				map.put(resourcePath, mark+","+authorityMark);
			}else{
				map.put(resourcePath, authorityMark);
			}
		}
		return map;
	}
	
	protected Map<RequestMatcher, Collection<ConfigAttribute>> bindRequestMap(){
		Map<RequestMatcher, Collection<ConfigAttribute>> map = 
				new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
		
		Map<String,String> resMap = this.loadResuorce();
		for(Map.Entry<String,String> entry:resMap.entrySet()){
			String key = entry.getKey();
			Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
			atts = SecurityConfig.createListFromCommaDelimitedString(entry.getValue());
			map.put(new AntPathRequestMatcher(key), atts);
		}
		
		return map;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		this.requestMap = this.bindRequestMap();
		logger.info("资源权限列表"+this.requestMap);
	}
	
	public void refreshResuorceMap(){
		this.requestMap = this.bindRequestMap();
	}

}

bindRequestMap需要在类初始化的时候就完成,但是这个不能写在构造函数中,因为构造函数执行是SysResourceRepository还没有注入过来。所以就通过实现InitializingBean把初始化操作放在afterPropertiesSet方法中。

getAllConfigAttributes:获取所有权限集合

getAttributes:根据request请求获取访问资源所需权限

代码很简单,很容易看懂,就不再多做解释,下面看配置文件

<sec:http auto-config="true" access-decision-manager-ref="accessDecisionManager">
		
		<sec:access-denied-handler ref="accessDeniedHandler"/>
		
		<sec:session-management invalid-session-url="/login.jsp" />
		
		<sec:form-login login-page="/login.jsp"
			login-processing-url="/login.do"
			authentication-failure-url="/login.jsp"
			authentication-success-handler-ref="authenticationSuccessHandler"
		/>
		
		<sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
			
	</sec:http>

	<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
		<property name="accessDecisionManager" ref="accessDecisionManager" />
		<property name="authenticationManager" ref="authenticationManager" />
		<property name="securityMetadataSource" ref="securityMetadataSource" />
	</bean>
	
	<bean id="securityMetadataSource"
		class="com.zrhis.system.security.URLFilterInvocationSecurityMetadataSource"/>

通过配置custom-filter来增加过滤器,before="FILTER_SECURITY_INTERCEPTOR"表示在SpringSecurity默认的过滤器之前执行。

FilterSecurityInterceptor还用SpringSecurity默认的就可以了,这个是没有必要自己写的只要在SecurityMetadataSource处理好资源与权限的对应关系就可以了。

到此为止SpringSecurity框架已基本完善,可以说在项目中用已经没什么问题了。

相关文章