事实上,spring 的命名空间处理程序在内部定义了名称_formLoginFilter
为 AuthenticationProcessingFilter 的 bean(参见BeanIds完整列表)。有多种方法可以解决此问题(即使用 DaoAuthenticationProvider 中的 j_username 以外的其他内容进行身份验证,例如从标头中获取用户名等...)
使用 Spring AOPbean()
语法进行拦截doFilter()
_formLoginFilter
定义一个切入点,用 name和 interceptsdoFilter
方法查找 bean 。( 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>
使用 CustomWebAuthenticationDetails 进行身份验证
为 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" />
使用线程绑定请求进行实际身份验证(在 DaoAuthenticationProvider 内)
使用 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();
}