Spring security(2.0.x)http命名空间,form-login定义自动使用AuthenticationProcessingFilter。
<form-login login-page='/logon.jsp'
default-target-url='/home.jsp'
always-use-default-target='true' />
我也知道,如果我设置auto-config="false"
,我可以通过提供自定义bean定义来自定义身份验证。
我有CustomAuthenticationProcessingFilter,它扩展了AuthenticationProcessingFilter,覆盖了acquireUsername,并使用自定义逻辑获取用户名而不是传递的用户名。
protected String obtainUsername(HttpServletRequest request) {
// custom logic to return username from parameter/cookies/header etc ...
}
是否可以在使用auto-config="true" <form-login>
的同时使用CustomAuthenticationProcessingFilter而无需定义customAuthFilter和所有依赖bean?
<beans:bean id="customAuthFilter" class="x.y.z.CustomAuthenticationProcessingFilter">
<custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<beans:property name="defaultTargetUrl" value="/home.jsp"></beans:property>
...
...
</beans:bean>
答案 0 :(得分:1)
Spring Security 2.0处于维护模式,因此不会有任何官方更新。但是,您可以使用一些方法来解决此问题。
您可以从Spring Security FAQ使用的技巧是使用BeanPostProcessor。您可以返回自定义过滤器,而不是修改属性。一个例子可能是这样的:
public class CustomFilterBeanPostProcessor implements BeanPostProcessor {
private Filter customFilter;
public Object postProcessAfterInitialization(Object bean, String name) {
if (bean instanceof AuthenticationProcessingFilter) {
return customFilter;
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String name) {
return bean;
}
public void setFilter(Filter filter) {
this.customFilter = filter;
}
}
然后您的配置将包括以下内容:
<beans:bean class="CustomFilterBeanPostProcessor">
<beans:property name="filter" ref="customAuthFilter"/>
</beans:bean>
另一种方法是在AuthenticationProcessingFilter之前插入自定义Filter。这将有一个额外的过滤器,但它应该是微创的,因为它很小并且不应该到达(即,因为自定义过滤器仅在AuthenticationProcessingFilter忽略请求时继续FilterChain)。使用此方法的示例配置如下所示:
<beans:bean id="customAuthFilter" class="x.y.z.CustomAuthenticationProcessingFilter">
<custom-filter before="AUTHENTICATION_PROCESSING_FILTER" />
<beans:property name="defaultTargetUrl" value="/home.jsp"></beans:property>
...
...
</beans:bean>
答案 1 :(得分:0)
唉,正如它出现的那样(如果我没有错),由于AuthenticationProcessingFilter类名在<HttpSecurityBeanDefinitionParser
>中被硬编码,所以无法做多少:(
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser =
new FormLoginBeanDefinitionParser("/j_spring_security_check",
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
如果过滤器类是一个配置属性并且可以在外部进行控制(就像default-target-url
那样)会更好
可能正在使用属性authentication-filter-class
<form-login login-page='/logon.jsp'
default-target-url='/home.jsp'
always-use-default-target='true'
authentication-filter-class='x.y.z.CustomAuthenticationProcessingFilter'
/>
希望春天的人们正在倾听;)
答案 2 :(得分:0)
事实是,spring的命名空间处理程序在内部为AuthenticationProcessingFilter定义了名为_formLoginFilter
的bean(参见BeanIds完整列表)。有一些方法可以解决这个问题(即使用DaoAuthenticationProvider中的j_username之外的其他东西进行身份验证,比如说从头部获取用户名等等)。
bean()
语法拦截doFilter()
定义一个切入点,查找名称为_formLoginFilter
的bean并截取doFilter
方法。 (AuthenticationProcessingFilter.doFilter() method
)并有条件地委托其他人
public class AuthenticationProcessingFilterAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationProcessingFilterAspect.class);
public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
LOGGER.info("intercept------------------{}",pjp.toLongString());
//Delegate to customised method instead of default pjp.proceed()
return pjp.proceed();
}
}
<强>配置强>
<beans:bean id="authFilterAspect" class="x.y.z.AuthenticationProcessingFilterAspect" />
<aop:config>
<aop:aspect ref="authFilterAspect">
<aop:around pointcut="bean(_formLoginFilter) && execution(* doFilter(..))" method="intercept"/>
</aop:aspect>
</aop:config>
为AuthenticationProcessingFilter bean定义一个bean后处理器,它注入了填充自定义字段的CustomWebAuthenticationDetails
public class AuthenticationProcessingFilterBeanPostProcessor implements
BeanPostProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationProcessingFilterBeanPostProcessor.class);
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if ("_formLoginFilter".equals(beanName) && bean instanceof AuthenticationProcessingFilter) {
AuthenticationProcessingFilter filter = (AuthenticationProcessingFilter) bean;
WebAuthenticationDetailsSource source = (WebAuthenticationDetailsSource) filter.getAuthenticationDetailsSource();
source.setClazz(CustomWebAuthenticationDetails.class);
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@SuppressWarnings("serial")
public static class CustomWebAuthenticationDetails extends
WebAuthenticationDetails {
private String customAttribute;//customfield
public CustomWebAuthenticationDetails(HttpServletRequest request) {
super(request);
//Build custom attributes that could be used elsewhere (say in DaoAuthenticationProvider )
//with (CustomWebAuthenticationDetails)authentication.getDetails()
customAttribute = request.getHeader("username");
}
public boolean getCustomAttribute() {
return customAttribute;
}
}
}
<强>配置强>
<beans:bean id="authFilterProcessor" class="x.y.z.AuthenticationProcessingFilterBeanPostProcessor" />
使用getHttpServletRequest()访问threadbound请求对象,并使用request.getHeader(“username”)进行自定义身份验证。
public static HttpServletRequest getHttpServletRequest(){
return((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}
如果请求不是通过DispatcherServlet
,还需要在web.xml中定义它<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/j_spring_security_check</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/j_spring_security_logout</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
如果其面部应用程序使用FacesContext.getCurrentInstance()
public static HttpServletRequest getHttpServletRequest(){
FacesContext context = FacesContext.getCurrentInstance();
return (HttpServletRequest) context.getExternalContext().getRequest();
}