[英]Using Custom AuthenticationProcessingFilter with <form-login> (auto-config=“true”)
Spring安全性(2.0.x)http名称空间,表单登录定义自动使用AuthenticationProcessingFilter。
<form-login login-page='/logon.jsp'
default-target-url='/home.jsp'
always-use-default-target='true' />
我也知道,如果设置auto-config="false"
,则可以通过提供自定义bean定义来自定义身份验证。
我有CustomAuthenticationProcessingFilter,它扩展了AuthenticationProcessingFilter覆盖了getUsername并使用自定义逻辑来获取比传递的用户名更多的用户名。
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>
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之前插入自定义过滤器。 这将有一个额外的过滤器,但由于它很小并且永远都不会达到(因此,自定义过滤器仅在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>
las,看来(如果我没记错的话),由于AuthenticationProcessingFilter类名称被硬编码在< HttpSecurityBeanDefinitionParser
> :(
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser =
new FormLoginBeanDefinitionParser("/j_spring_security_check",
"org.springframework.security.ui.webapp.AuthenticationProcessingFilter");
。
。
如果filter类是一个config属性,并且在外部进行控制(就像default-target-url
)可能使用attribute 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'
/>
希望春天的人们在听;)
事实是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后处理器,该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()访问线程绑定的请求对象,并使用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();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.