接着来。
2.过滤器的配置:
我们已经配置了那些过滤器了,但是要跟spring context中的对象对应,于是乎,做了如下配置:
<beans:bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
</beans:bean>
<beans:bean id="logoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter" >
<beans:constructor-arg type="java.lang.String" value="/"/>
<beans:constructor-arg ref="securityContextLogoutHandler"/>
</beans:bean>
<beans:bean id="basicAuthenticationFilter"
class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"></beans:property>
<beans:property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"></beans:property>
</beans:bean>
<beans:bean id="requestCacheAwareFilter"
class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter">
</beans:bean>
<beans:bean id="securityContextHolderAwareRequestFilter"
class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter">
</beans:bean>
<beans:bean id="anonymousAuthenticationFilter"
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<beans:property name="userAttribute" ref="anonymousUserAttribute"></beans:property>
<beans:property name="key" value="anonymousUser"/>
</beans:bean>
<beans:bean id="sessionManagementFilter"
class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg type="org.springframework.security.web.context.SecurityContextRepository" ref="sessionSecurityContextRepository"/>
</beans:bean>
<beans:bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="authenticationProcessingFilterEntryPoint"/>
</beans:bean>
<beans:bean id="filterSecurityInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<beans:property name="securityMetadataSource" ref="securityMetadataSource" />
</beans:bean>
<!-- The following beans are configured for the filters upstairs -->
<!-- ///////////////////////////////////////// -->
<!-- ////for LogoutFilter///////////////////// -->
<!-- ///////////////////////////////////////// -->
<beans:bean id="securityContextLogoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
</beans:bean>
<!-- ///////////////////////////////////////// -->
<!-- ////for AnonymousAuthenticationFilter//// -->
<!-- ///////////////////////////////////////// -->
<beans:bean id="anonymousUserAttribute"
class="org.springframework.security.core.userdetails.memory.UserAttribute">
<beans:property name="authorities">
<beans:list>
<beans:ref bean="anonymousUserGrantedAuthority" />
</beans:list>
</beans:property>
<beans:property name="password" value="anonymousUser"/>
</beans:bean>
<beans:bean id="anonymousUserGrantedAuthority"
class="org.springframework.security.core.authority.GrantedAuthorityImpl">
<beans:constructor-arg type="java.lang.String" value="ROLE_ANONYMOUS"/>
</beans:bean>
<!-- ///////////////////////////////////////// -->
<!-- ////for SessionManagementFilter////////// -->
<!-- ///////////////////////////////////////// -->
<beans:bean id="sessionSecurityContextRepository"
class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
</beans:bean>
<!-- ///////////////////////////////////////// -->
<!-- ////for FilterSecurityInterceptor//////// -->
<!-- ///////////////////////////////////////// -->
<beans:bean id="accessDecisionManager"
class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:ref bean="webExpressionVoter"/>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="webExpressionVoter"
class="com.saveworld.authentication.web.access.expression.MyWebExpressionVoter">
</beans:bean>
<beans:bean id="securityMetadataSource"
class="com.saveworld.authentication.web.access.intercept.MyFilterInvocationSecurityMetadataSource">
<beans:constructor-arg type="org.springframework.security.web.util.UrlMatcher" ref="urlMatcher" />
<beans:constructor-arg type="javax.sql.DataSource" ref="proxoolDataSource" />
<beans:constructor-arg type="org.springframework.security.web.access.expression.WebSecurityExpressionHandler"
ref="expressionHandler" />
</beans:bean>
<beans:bean id="urlMatcher"
class="org.springframework.security.web.util.AntUrlPathMatcher" >
<beans:constructor-arg type="boolean" value="true" />
</beans:bean>
<beans:bean id="expressionHandler"
class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
</beans:bean>
这里做几点说明:
(1) 数据库中的权限相关的表:
ROLES
AUTHORITIES
USER_AUTHS
ROLE_AUTHS
USERS
这里的表结构还不是最终的,所以就不发上来误导兄弟姐妹们了。
关键是看我们如何加载这些持久化的东西。
这个就要看看filterSecurityInterceptor了,它里面使用了一个securityMetadataSource,本地的securityMetadataSource实现代码:
public class MyFilterInvocationSecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource{
private final static Log logger = LogFactory.getLog(ExpressionBasedFilterInvocationSecurityMetadataSource.class);
private DataSource datasource;
public MyFilterInvocationSecurityMetadataSource(UrlMatcher urlMatcher,
DataSource datasource,
WebSecurityExpressionHandler expressionHandler) {
super(urlMatcher, processMap(initializeFromDb(datasource,null),expressionHandler.getExpressionParser()));
}
//This method is usefulless for now!
//Because this method is used for parsing the expression kind
private static LinkedHashMap<RequestKey, Collection<ConfigAttribute>> processMap(
LinkedHashMap<RequestKey,Collection<ConfigAttribute>> requestMap, ExpressionParser parser) {
Assert.notNull(parser, "SecurityExpressionHandler returned a null parser object");
LinkedHashMap<RequestKey, Collection<ConfigAttribute>> requestToExpressionAttributesMap =
new LinkedHashMap<RequestKey, Collection<ConfigAttribute>>(requestMap);
for (Map.Entry<RequestKey, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
RequestKey request = entry.getKey();
Assert.isTrue(entry.getValue().size() == 1, "Expected a single expression attribute for " + request);
ArrayList<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>(1);
String expression = entry.getValue().toArray(new ConfigAttribute[1])[0].getAttribute();
logger.debug("Adding web access control expression '" + expression + "', for " + request);
try {
//Replacing WebExpressionConfigAttribute with MyWebExpressionConfigAttribute
//which is defined locally!
attributes.add(new MyWebExpressionConfigAttribute(parser.parseExpression(expression)));
} catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression '" + expression + "'");
}
requestToExpressionAttributesMap.put(request, attributes);
}
return requestToExpressionAttributesMap;
}
private static LinkedHashMap<RequestKey,Collection<ConfigAttribute>> initializeFromDb(DataSource datasource,LinkedHashMap<RequestKey, Collection<ConfigAttribute>> configMap){
LinkedHashMap<RequestKey,Collection<ConfigAttribute>> result =
new LinkedHashMap<RequestKey, Collection<ConfigAttribute>>();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = datasource.getConnection();
stmt = conn.createStatement();
StringBuilder sql = new StringBuilder("SELECT b.AUTHORITYPATTERN ,'hasRole('||chr(39)||a.ROLENAME||chr(39)||')' rolename ")
.append(" FROM ROLES a,AUTHORITIES b,ROLE_AUTHS c ")
.append(" WHERE a.rolename = c.rolename AND b.authorityname = c.authorityname");
rs = stmt.executeQuery(sql.toString());
String roles = "";
RequestKey key = null;
List<ConfigAttribute> value = null;
while(rs != null && rs.next()){
key = new RequestKey(rs.getString(1));
roles = rs.getString(2);
String[] roleArray = roles.split(",|\\s+|;");
value = new ArrayList<ConfigAttribute>();
for(String role : roleArray){
ConfigAttribute config = new SecurityConfig(role);
value.add(config);
}
result.put(key, value);
}
//just for test
} catch (SQLException e) {
e.printStackTrace();
} finally{
try{
rs.close();
stmt.close();
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
return result;
}
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
public DataSource getDatasource() {
return datasource;
}
public void setDatasource(DataSource datasource) {
this.datasource = datasource;
}
}
(2) expressionHandler:
这个东西要单独说说,我这里用的是表达式来检测用户角色的,所以,我用org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler来处理了,还有其他的方式,就是直接用角色进行判断,那样会更好,这里就不描述了!