我正在尝试使用<authorize>
标签的spring security的“url”属性。我遇到了一个奇怪的情况,标签似乎没有生效。
我的业务需要是使用两个<http>
元素,一个用于 Web 服务访问,另一个用于普通用户访问:Web 服务访问是无状态的,但用户访问是基于会话的,这就是我们需要两个 http 元素的原因。
为了说明这个问题,我将使用 spring security 3.1.4 教程来代替。<http>
我可以通过只在 spring 配置文件中添加一个额外的元素来重现这个问题。
教程中的原始 applicationContext-securiy.xml 定义如下:
<http pattern="/static/**" security="none"/>
<http pattern="/loggedout.jsp" security="none"/>
<http use-expressions="true">
<intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
<intercept-url pattern="/secure/**" access="isAuthenticated()" />
....
</http>
它的登录页面 index.jsp 使用“授权”标签,如下所示:
<sec:authorize url='/secure/index.jsp'>
<p>
You can currently access "/secure" URLs.
</p>
</sec:authorize>
当用户第一次尝试访问此页面时,标签将检查对 url '/secure/index.jsp' 的权限,这需要身份验证,因此标签不会取代其内容和 UI 显示消息。
您的主要对象是....:null
现在,通过在最后一个“http”元素之前添加一个新的 http 元素来更改 applicationContext-security.xml
<http pattern="/static/**" security="none"/>
<http pattern="/loggedout.jsp" security="none"/>
<!--This is the new element added-->
<http pattern="/user/**"
use-expressions="true">
<intercept-url pattern="/user/**" access="hasRole('user')"/>
<http-basic />
</http>
<http use-expressions="true">
<intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
<intercept-url pattern="/secure/**" access="isAuthenticated()" />
....
</http>
现在,我访问 index.jsp(还没有登录),页面实际上打印出一条消息:
您的主要对象是....: null 您当前可以访问“/secure” URL。您当前可以访问“/secure/extreme” URL。
在这种情况下,“授权”标签的计算结果为真,即使我还没有登录!
我尝试通过源代码DefaultFilterInvocationSecurityMetadataSource进行调试,发现当第一个http请求“/index.jsp”进来时,它使用applicationContext-security.xml中的默认元素(最后一个)但是当“”标签尝试检查对“/secure/index.jsp”的访问,DefaultFilterInvocationSecurityMetadataSource 正在使用新元素,它的 getAttributes() 返回 null 到 DefaultWebInvocationPrivilegeEvaluator,最终返回 true。
这对我来说看起来像是一个弹簧安全错误:授权标签 url,“/secure/index.jsp”应该匹配默认的“http”,而不是另一个。
我使用的一种解决方法是将“/secure/index.jsp”和“/secure/extreme/index.jsp”的“intercept-url”定义从默认的“http”复制到新的“http”元素,然后UI 按预期工作。但我不想复制代码!
任何想法都值得赞赏。