Spring,属性文件,空值

Spring,属性文件,空值,spring,spring-security,placeholder,Spring,Spring Security,Placeholder,我已经用ldap服务器配置了spring安全性(但请继续阅读,如果您不了解它,这不是问题,这实际上是spring的问题)。一切都像一个符咒。以下是我使用的一行: <ldap-server ldif="" root="" manager-dn="" manager-password="" url="" id="ldapServer" /> 现在,问题的有趣部分。如果我在文件中填写以下属性: ldap.server.url=ldap://myldapserver.com/dc=spr

我已经用ldap服务器配置了spring安全性(但请继续阅读,如果您不了解它,这不是问题,这实际上是spring的问题)。一切都像一个符咒。以下是我使用的一行:

<ldap-server ldif="" root="" manager-dn="" manager-password="" url=""  id="ldapServer" />
现在,问题的有趣部分。如果我在文件中填写以下属性:

ldap.server.url=ldap://myldapserver.com/dc=springframeworg,dc=org
ldap.server.manager.dn=dc=admin,dc=springframeworg,dc=org
ldap.server.manager.password=password

ldap.ldif.path= 
ldap.ldif.root= 
它按预期运行远程服务器

如果我像这样填充属性文件:

<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}"  id="ldapServer" />
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=

ldap.ldif.path= classpath:ldap.ldif
ldap.ldif.root= dc=springframeworg,dc=org
它没有运行,抱怨ldap url丢失。但问题是,如果我将spring配置更改为:

<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}"  id="ldapServer" />

to(只需删除对变量${ldap.server.url}的引用)


它跑了

我的想法是,如果属性config值为空,spring不会用属性config值替换属性值。但我觉得很奇怪

你能给我一些线索让我明白吗?通过属性文件配置ldap服务器的最佳方法是什么

编辑:这是由于设计选择不当(请查看已接受的答案),jira出现了一个问题:

我无法解释,但我认为您可以使用自Spring 3.0.0.RC1()以来提供的默认语法解决问题

在chageg日志中,您可以阅读:PropertyPlaceHolderConfigure支持“${myKey:myDefaultValue}”默认语法

无论如何,我认为问题是因为“”是有效值,但属性文件中的任何值都不是有效值。

我认为
url=”“
有效,因为
url
属性在spring security XSD中属于
xs:token
类型,空字符串被转换为
null
xs:token
正在删除任何前导空格或尾随空格,因此可以将
识别为无值)。可能
${ldap.server.url}
的值被解析为空字符串,这就是出现错误的原因


您可以尝试使用Spring配置文件来定义ldap服务器的不同配置(有关配置文件的详细信息,请参阅)

我认为在使用占位符时会出现问题。以下内容很可能会解决此问题:

创建一个扩展PropertyPlaceHolderConfigure并重写其方法convertPropertyValue()的类 在该方法中,如果您找到的不是LDAP url类型的字符串,即。ldap://myldapserver.com/dc=springframeworg,dc=org

此外,还需要在上下文文件中配置类PropertyPlaceHolderConfigure的新专门化


希望这有帮助。

好的,我认为这是一个spring安全漏洞

如果我调试并查看LdapServerBeanDefinition类,则有一个名为“parse”的方法。以下是摘录:

public BeanDefinition parse(Element elt, ParserContext parserContext) {
    String url = elt.getAttribute(ATT_URL);

    RootBeanDefinition contextSource;

    if (!StringUtils.hasText(url)) {
        contextSource = createEmbeddedServer(elt, parserContext);
    } else {
        contextSource = new RootBeanDefinition();
        contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
        contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
    }

    contextSource.setSource(parserContext.extractSource(elt));

    String managerDn = elt.getAttribute(ATT_PRINCIPAL);
    String managerPassword = elt.getAttribute(ATT_PASSWORD);

    if (StringUtils.hasText(managerDn)) {
        if(!StringUtils.hasText(managerPassword)) {
            parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
                    " if you supply a " + managerDn, elt);
        }

        contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
        contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
    }

    ...
}
如果我在这里调试,所有变量(url、managerDn、managerPassword…)都不会被属性文件中指定的值替换。因此,url的值为${ldap.server.url},managerDn的值为${ldap.server.manager.dn},依此类推

parse方法创建一个bean,一个将被进一步使用的上下文源。当使用这个bean时,将替换占位符

在这里,我们发现了错误。解析方法检查url是否为空。问题是url在这里不是空的,因为它的值为${ldap.server.url}。因此,解析方法创建了一个上下文源作为远程服务器

当使用创建的源代码时,它会将${ldap.server.url}替换为空值(就像在属性文件中指定的那样)


我现在不知道如何解决这个问题,但我现在明白了它为什么会出错;)

您可以在
应用程序.properties
文件中定义空的
字符串,如下所示:

com.core.estimation.stopwords=\\

谢谢你的回答,但我总是使用默认值提示来解决同样的问题。我不明白。如果默认值为“”,我认为应该与将其设置为“”相同。是的,我也这么认为。。。这很奇怪。。。也许,只有在使用spring表达式时才会调用url的setter,而使用空值调用setter会导致错误。如果不指定表达式,可能不会调用setter?您使用的是哪一版本的Spring?LdapServerBeanDefinitionParser已经在处理它了。不知何故,它成功地创建了org.springframework.security.ldap.DefaultSpringSecurityContextSource的bean定义,构造函数中的URL为空,尽管所有检查似乎都已到位以防止它。我想我已经找到了Ritesh正确的原因和它不运行的原因:当我调试服务器启动时(在LdapServerBeanDefinition的方法解析中),不会替换所有占位符。因此url为:${ldap.server.url}。占位符的解析在创建上下文源之后完成。根据文档,如果我们要创建嵌入式服务器,则根本不应使用url属性。这不是错误。如果要创建嵌入式服务器,则不应使用url属性。请参阅我所称的错误,即使用空字符串运行d使用变量不会运行,因为spring安全性通过不将变量替换为其值(可以为空!)来检查url是否为空。这是一个糟糕的设计。在这种情况下,我认为在spring bug tracker中报告问题是有意义的,对吧?感谢您提交了问题,我将在今晚或明天完成;)
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=

ldap.ldif.path= classpath:ldap.ldif
ldap.ldif.root= dc=springframeworg,dc=org
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}"  id="ldapServer" />
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url=""  id="ldapServer" />
public BeanDefinition parse(Element elt, ParserContext parserContext) {
    String url = elt.getAttribute(ATT_URL);

    RootBeanDefinition contextSource;

    if (!StringUtils.hasText(url)) {
        contextSource = createEmbeddedServer(elt, parserContext);
    } else {
        contextSource = new RootBeanDefinition();
        contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
        contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
    }

    contextSource.setSource(parserContext.extractSource(elt));

    String managerDn = elt.getAttribute(ATT_PRINCIPAL);
    String managerPassword = elt.getAttribute(ATT_PASSWORD);

    if (StringUtils.hasText(managerDn)) {
        if(!StringUtils.hasText(managerPassword)) {
            parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
                    " if you supply a " + managerDn, elt);
        }

        contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
        contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
    }

    ...
}