这个可以说是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框架已基本完善,可以说在项目中用已经没什么问题了。
- 前言
- (大纲)----学习过程分享
- (1)----SpringSecurity3.2环境搭建
- (2)----SpringSecurity简单测试
- (3)---- 自定义登录页面
- (4)---- 数据库表结构的创建
- (5)---- 国际化配置及UserCache
- (6)---- 使用数据库管理用户及权限
- (7)---- 解决UsernameNotFoundException无法被捕获的问题
- (8)---- 自定义决策管理器及修改权限前缀
- (9)---- 自定义AccessDeniedHandler
- (10)---- 自定义登录成功后的处理程序及修改默认验证地址
- (11)---- 使用数据库来管理资源
- (12)---- 使用数据库来管理方法
- (13)---- 验证码功能的实现
- (14)---- Logout和SessionManager