這個可以說是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