我正在尝试使用<authorize>
标记的spring security的“url”属性。我陷入一种奇怪的情况,标签似乎没有生效。
我的业务需求是使用两个<http>
元素,一个用于Web服务访问,另一个用于普通用户访问:Web服务访问是无状态的,但用户访问是基于会话的,这就是我们需要两个http的原因元素。
为了说明这个问题,我将使用spring security 3.1.4教程。我可以通过在spring配置文件中添加一个额外的<http>
元素来重现此问题。
教程中的原始applicationContext-secutiry.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使用“authorize”标签,如下所示:
<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”网址。 您当前可以访问“/ secure / extreme”网址。
在这种情况下,“authorize”标签的评估结果为true,即使我还没有登录!
我尝试通过源代码DefaultFilterInvocationSecurityMetadataSource调试,并发现当第一个http请求“/index.jsp”进来时,它使用applicationContext-security.xml中的默认元素(最后一个)但是当“”标签尝试检查对“/secure/index.jsp”的访问,DefaultFilterInvocationSecurityMetadataSource使用新元素,其getAttributes()返回null到DefaultWebInvocationPrivilegeEvaluator,最终返回true。
对我来说,这看起来像是一个弹簧安全漏洞:授权标记网址“/secure/index.jsp”应该与默认的“http”匹配,而不是另一个。
我使用的一种解决方法是将“/secure/index.jsp”和“/secure/extreme/index.jsp”的“intercept-url”定义从默认的“http”复制到新的“http”元素然后UI按预期工作。但我不想复制代码!
任何想法都表示赞赏。
答案 0 :(得分:1)
我已解决此问题如下。
Java:
package com.github.kazuki43zoo.web.security;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.stereotype.Component;
@Component
public class CustomWebInvocationPrivilegeEvaluatorProvideFilter implements Filter,
WebInvocationPrivilegeEvaluator, BeanPostProcessor {
private List<WebInvocationPrivilegeEvaluator> webInvocationPrivilegeEvaluators = new ArrayList<>();
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setAttribute(WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE, this);
chain.doFilter(request, response);
}
@Override
public void destroy() {
webInvocationPrivilegeEvaluators.clear();
}
@Override
public boolean isAllowed(String uri, Authentication authentication) {
for (WebInvocationPrivilegeEvaluator privilegeEvaluator : webInvocationPrivilegeEvaluators) {
if (!privilegeEvaluator.isAllowed(uri, authentication)) {
return false;
}
}
return true;
}
@Override
public boolean isAllowed(String contextPath, String uri, String method,
Authentication authentication) {
for (WebInvocationPrivilegeEvaluator privilegeEvaluator : webInvocationPrivilegeEvaluators) {
if (!privilegeEvaluator.isAllowed(contextPath, uri, method, authentication)) {
return false;
}
}
return true;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WebInvocationPrivilegeEvaluator
&& !bean.getClass().isAssignableFrom(getClass())) {
webInvocationPrivilegeEvaluators.add((WebInvocationPrivilegeEvaluator) bean);
}
return bean;
}
}
的web.xml:
<filter>
<filter-name>CustomWebInvocationPrivilegeEvaluatorProvideFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>customWebInvocationPrivilegeEvaluatorProvideFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CustomWebInvocationPrivilegeEvaluatorProvideFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
答案 1 :(得分:0)
这对我有用:
org.springframework.context.ApplicationContext ctx = org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
java.util.Map<String, org.springframework.security.web.access.WebInvocationPrivilegeEvaluator>
wipes = ctx.getBeansOfType(org.springframework.security.web.access.WebInvocationPrivilegeEvaluator.class);
if(wipes.size() > 0){
//I need last one
org.springframework.security.web.access.WebInvocationPrivilegeEvaluator appEvaluator =
(WebInvocationPrivilegeEvaluator)wipes.values().toArray()[wipes.size() - 1];
//set request attribute so that JSP tag can use it request.setAttribute(org.springframework.security.web.WebAttributes.WEB_INVOCATION_PRIVILEGE_EVALUATOR_ATTRIBUTE
, appEvaluator);
}