Acegi中的FilterInvocationDefinitionMap提供两种实现:PATTERN_TYPE_ANT_PATH及PATTERN_TYPE_PERL5。其中PATTERN_TYPE_ANT_PATH使用apache Ant的路径格式来进行url的模式匹配,由于只有**, *, ?少数几个通配符,所以使用起来比较简单,但是无法支持带参数的url,如/action.do?method=m这种url,在进行匹配之前,会先将?后面的部分截去。见PathBasedFilterInvocationDefinitionMap.java的代码:
在对Acegi的缺省实现不进行扩展的情况下,要实现对带参数URL的安全控制,可以使用PATTERN_TYPE_PERL5即正则表达式进行模式匹配(在RegExpBasedFilterInvocationDefinitionMap中实现),例如上述的路径可以用如下的模式来进行匹配:^/user\.do\?method=.*,采用这种方案的优点是可以利用正则表达式的强大表达能力,缺点是难以实现模式的自动生成。在一个实用的基于角色的权限管理体系中,通常对要进行安全控制的资源是由管理员通过管理界面来定制的,如果使用PATTERN_TYPE_PERL5的格式来制定模式,则需要管理员熟练掌握正则表达式的使用,有难度。考虑实现一个UrlFilterInvocationDefinitionMap,仅提供一种通配符*,又支持url参数,简单又实用。代码如下:
其中模式匹配用了一个UrlMatcher类,代码及test列在下面:
这下可以爽了。
java 代码
- public ConfigAttributeDefinition lookupAttributes(String url) {
- // Strip anything after a question mark symbol, as per SEC-161. See also SEC-321
- int firstQuestionMarkIndex = url.indexOf("?");
- if (firstQuestionMarkIndex != -1) {
- url = url.substring(0, firstQuestionMarkIndex);
- }
- if (isConvertUrlToLowercaseBeforeComparison()) {
- url = url.toLowerCase();
- if (logger.isDebugEnabled()) {
- logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
- }
- }
- Iterator iter = requestMap.iterator();
- while (iter.hasNext()) {
- EntryHolder entryHolder = (EntryHolder) iter.next();
- boolean matched = pathMatcher.match(entryHolder.getAntPath(), url);
- if (logger.isDebugEnabled()) {
- logger.debug("Candidate is: '" + url + "'; pattern is " + entryHolder.getAntPath() + "; matched="
- + matched);
- }
- if (matched) {
- return entryHolder.getConfigAttributeDefinition();
- }
- }
- return null;
- }
java 代码
- import org.acegisecurity.ConfigAttributeDefinition;
- import org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource;
- import org.acegisecurity.intercept.web.FilterInvocationDefinition;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import java.util.*;
- /**
- * User: user
- * Date: 2007-4-11
- * Time: 9:14:00
- */
- public class UrlFilterInvocationDefinitionMap extends AbstractFilterInvocationDefinitionSource
- implements FilterInvocationDefinition {
- private static final Log logger = LogFactory.getLog(UrlFilterInvocationDefinitionMap.class);
- private List<EntryHolder> requestMap = new ArrayList<EntryHolder>();
- private boolean convertUrlToLowercaseBeforeComparison = false;
- public ConfigAttributeDefinition lookupAttributes(String url) {
- Iterator iter = requestMap.iterator();
- if (isConvertUrlToLowercaseBeforeComparison()) {
- url = url.toLowerCase();
- if (logger.isDebugEnabled()) {
- logger.debug("Converted URL to lowercase, from: '" + url + "'; to: '" + url + "'");
- }
- }
- while (iter.hasNext()) {
- EntryHolder entryHolder = (EntryHolder) iter.next();
- boolean matched = UrlMatcher.matches(url, entryHolder.getUrlPattern());
- if (logger.isDebugEnabled()) {
- logger.debug("Candidate is: '" + url + "'; pattern is " + entryHolder.getUrlPattern()
- + "; matched=" + matched);
- }
- if (matched) {
- return entryHolder.getConfigAttributeDefinition();
- }
- }
- return null;
- }
- public Iterator getConfigAttributeDefinitions() {
- Set<ConfigAttributeDefinition> set = new HashSet<ConfigAttributeDefinition>();
- for (EntryHolder aRequestMap : requestMap) {
- set.add(aRequestMap.getConfigAttributeDefinition());
- }
- return set.iterator();
- }
- public void addSecureUrl(String urlPattern, ConfigAttributeDefinition attr) {
- requestMap.add(new EntryHolder(urlPattern, attr));
- if (logger.isDebugEnabled()) {
- logger.debug("Added url pattern: " + urlPattern + "; attributes: " + attr);
- }
- }
- public boolean isConvertUrlToLowercaseBeforeComparison() {
- return this.convertUrlToLowercaseBeforeComparison;
- }
- public void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison) {
- this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
- }
- protected class EntryHolder {
- private ConfigAttributeDefinition configAttributeDefinition;
- private String urlPattern;
- public EntryHolder(String urlPattern, ConfigAttributeDefinition attr) {
- this.urlPattern = urlPattern;
- this.configAttributeDefinition = attr;
- }
- protected EntryHolder() {
- throw new IllegalArgumentException("Cannot use default constructor");
- }
- public String getUrlPattern() {
- return urlPattern;
- }
- public ConfigAttributeDefinition getConfigAttributeDefinition() {
- return configAttributeDefinition;
- }
- }
- }
java 代码
- import java.util.regex.Pattern;
- import java.util.regex.Matcher;
- /**
- * User: user
- * Date: 2007-4-11
- * Time: 9:48:09
- */
- public class UrlMatcher {
- public static boolean matches(String url, String urlPattern){
- StringBuffer buff = new StringBuffer();
- buff.append('^');
- buff.append(urlPattern.replaceAll("\\.", "\\\\.").replaceAll("\\?", "\\\\?").replaceAll("\\*", ".*"));
- buff.append("$");
- Pattern pattern = Pattern.compile(buff.toString());
- Matcher matcher = pattern.matcher(url);
- boolean found = matcher.find();
- return found && matcher.group().equals(url);
- }
- }
java 代码
- /**
- * User: user
- * Date: 2007-4-11
- * Time: 10:07:07
- */
- import junit.framework.*;
- import com.vnv.basicacegi.security.UrlMatcher;
- public class UrlMatcherTest extends TestCase {
- public void testMatches() throws Exception {
- assertTrue(UrlMatcher.matches("/user.do?method=home", "/user.do?method=*"));
- assertTrue(UrlMatcher.matches("/user/home/abc/action.do", "/user/*/action.do"));
- assertTrue(UrlMatcher.matches("/user/home/abc/action.do?method=a&c=d", "/user/*/action.do*"));
- assertTrue(UrlMatcher.matches("/user/home/abc/action.do?method=a&c=d", "/user/*/action.do?*"));
- assertTrue(UrlMatcher.matches("/user/home/abc/action.do?method=a&c=d", "/user/*/action.do?method=*"));
- assertFalse(UrlMatcher.matches("/user/action.do?method=a&c=d", "/user/*/action.do?method=*"));
- assertTrue(UrlMatcher.matches("/action.do?method=a&c=d", "*/action.do?method=*"));
- }
- }