之前也试着玩过springsecurity,这回把它搬到项目中,却遇到了意想不到的麻烦。我定义了一些角色与资源,下表显示了它们的情况:
Loginer Role Resource Description
admin ROLE_ADMIN /*/*.action 能访问所有的action资源
user ROLE_USER /index/index.action 仅能访问去首页的那个action
假设登录后就访问/index/index.action。我的目的是以admin登录的用户,它具有管理者的角色,并能访问所有的action资源;而以user登录的用户只能访问去首页的那个action资源。所以无论谁登录,都应该可以访问 /index/index.action资源。结果只有其中一个能成功!
先看一下用于判断是否有权限访问资源的那个类及相关代码:
package org.springframework.security.intercept.web;
....
public class DefaultFilterInvocationDefinitionSource implements FilterInvocationDefinitionSource {
....
private ConfigAttributeDefinition lookupUrlInMap(Map requestMap, String url) {
Iterator entries = requestMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
Object p = entry.getKey(); //这个相当于Resource
boolean matched = urlMatcher.pathMatchesUrl(p, url);
if (logger.isDebugEnabled()) {
logger.debug("Candidate is: '" + url + "'; pattern is " + p + "; matched=" + matched);
}
if (matched) {
//如果用户访问的资料与requestMap内定义的Resource匹配,就返回这个资源对应的所有角色。
//因为while循环,并且找到匹配后就返回,所以就永远只返回第一条匹配的Resource对应的所有角色了。
return (ConfigAttributeDefinition) entry.getValue(); ****(1)
}
}
return null;
}
....
}
package org.springframework.security.vote;
....
public class RoleVoter implements AccessDecisionVoter {
....
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
Iterator iter = config.getConfigAttributes().iterator(); //此迭代器的内容就是上边返回的匹配与当前请求的所有角色
GrantedAuthority[] authorities = extractAuthorities(authentication); //当前登录者拥有的所有角色
while (iter.hasNext()) {
ConfigAttribute attribute = (ConfigAttribute) iter.next(); //迭代器里的每个角色
if (this.supports(attribute)) {
result = ACCESS_DENIED;
//如果当前登录都其中一个角色与当前请求匹配的其中一个角色对应,就允许访问。
****(2)
for (int i = 0; i < authorities.length; i++) {
if (attribute.getAttribute().equals(authorities[i].getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
....
}
所以,结论如下:
在(1)处,如果第一条匹配的Resource对应的角色是ROLE_ADMIN,用user来登录的话,虽然他能够访问 /index/index.action,但user的角色是ROLE_USER,所以(2)处作判断的话就说他没权限访问了;
在(1)处,如果第一条匹配的Resource对应的角色是ROLE_USER,用admin来登录的话,虽然他能够访问 /index/index.action,但admin的角色是ROLE_ADMIN,所以(2)处作判断的话就说他没权限访问了。
最后的教训是,在定义资源的时候,不同的资源必须互不相干,如果象我上边那样一个资源能匹配另一个,就会出现无权访问资源的后果了。