使用自定义 AbstractAuthenticationProcessingFilter 和自定义 CustomAuthenticationProvider 的身份验证无法正常工作
Posted
技术标签:
【中文标题】使用自定义 AbstractAuthenticationProcessingFilter 和自定义 CustomAuthenticationProvider 的身份验证无法正常工作【英文标题】:Authentication using custom AbstractAuthenticationProcessingFilter and custom CustomAuthenticationProvider is not working propertly 【发布时间】:2013-03-04 16:42:29 【问题描述】:我们使用 spring security 根据来自外部应用程序的一些用户详细信息(如 userid )对用户进行身份验证,并使用安全上下文持有者执行授权。我们正在使用 AbstractAuthenticationProcessingFilter 的自定义实现和 CustomAuthenticationProvider 的自定义实现,并将我们自己的 UserDetailsServiceImpl 注入提供程序以从数据库中获取用户详细信息。
当单个用户尝试登录时,它工作正常,身份验证对象被创建并正确设置到 SecurityCONtextHolder。但是当另一个用户尝试登录时,旧的身份验证对象会被新的身份验证对象覆盖。看起来没有在每个用户登录时创建新会话。
过滤器和提供者的实现如下--
public class DefaultAuthenticationProcessingFilter extends
AbstractAuthenticationProcessingFilter
private final static Logger logger = LoggerFactory.getLogger(DefaultAuthenticationProcessingFilter.class);
private static final String INTERCEPTOR_PROCESS_URL = "/sso/landingpage.action";
public DefaultAuthenticationProcessingFilter()
super(INTERCEPTOR_PROCESS_URL);
public DefaultAuthenticationProcessingFilter(
String defaultFilterProcessesUrl)
super(defaultFilterProcessesUrl);
Assert.notNull(defaultFilterProcessesUrl, "Configuration error :: DefaultFilterProcessesUrl must be specified");
/**
* Method to do authentication of user
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException,
IOException, ServletException
logger.info("Authenticating the user .....");
Authentication authResult = null;
try
String eid = request.getParameter("EID");
if( StringUtils.isEmpty(eid))
throw new PreAuthenticatedCredentialsNotFoundException("EID param not found in request.");
String credentials = "NA";
PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken(eid, credentials);
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
authResult = getAuthenticationManager().authenticate(authRequest);
catch (AuthenticationException e)
unsuccessfulAuthentication(request, response, e);
return authResult;
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException, ServletException
if (logger.isDebugEnabled())
logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
SecurityContextHolder.getContext().setAuthentication(authResult);
getRememberMeServices().loginSuccess(request, response, authResult);
// Fire event
if (this.eventPublisher != null)
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
getSuccessHandler().onAuthenticationSuccess(request, response, authResult);
自定义提供者的实现如下 -
public class CustomAuthenticationProvider implements AuthenticationProvider, InitializingBean
private final static Logger logger = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedUserDetailsService = null;
/**
*
*/
public Authentication authenticate(Authentication authentication) throws AuthenticationException
if (!supports(authentication.getClass()))
return null;
if (logger.isDebugEnabled())
logger.debug("PreAuthenticated authentication request: " + authentication);
if (authentication.getPrincipal() == null)
logger.debug("No pre-authenticated principal found in request.");
return null;
UserDetails ud = preAuthenticatedUserDetailsService.loadUserDetails((PreAuthenticatedAuthenticationToken)authentication);
PreAuthenticatedAuthenticationToken result =
new PreAuthenticatedAuthenticationToken(ud, authentication.getCredentials(), ud.getAuthorities());
result.setDetails(authentication.getDetails());
return result;
@Override
public void afterPropertiesSet() throws Exception
// TODO Auto-generated method stub
@Override
public boolean supports(Class<?> authentication)
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
/**
* @return the preAuthenticatedUserDetailsService
*/
public AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getPreAuthenticatedUserDetailsService()
return preAuthenticatedUserDetailsService;
/**
* @param preAuthenticatedUserDetailsService the preAuthenticatedUserDetailsService to set
*/
public void setPreAuthenticatedUserDetailsService(
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> preAuthenticatedUserDetailsService)
this.preAuthenticatedUserDetailsService = preAuthenticatedUserDetailsService;
我们还配置了自定义身份验证成功处理程序,以在身份验证时将用户重定向到适当的 URL -
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler
/**
* redirect user to appropriate home page based on user role
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException
Set<GrantedAuthority> authorities = ((UserDetails)authentication.getPrincipal()).getAuthorities();
if(CollectionUtils.isNotEmpty(authorities))
GrantedAuthority role = getHighestRole(authorities);
String targetURL = getTargetURL(role);
if (targetURL != null)
log.debug("Redirecting to target Url: " + targetURL);
getRedirectStrategy().sendRedirect(request, response, targetURL);
return;
super.onAuthenticationSuccess(request, response, authentication);
spring 安全配置文件如下 -
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<security:http use-expressions="true" auto-config="false" pattern="/sso/*" entry-point-ref="http403ForbiddenEntryPoint" access-denied-page="/accessdenied.action" >
<security:anonymous enabled="false"/>
<security:custom-filter position="BASIC_AUTH_FILTER" ref="defaultBasicAuthFilter" />
<security:expression-handler ref="expressionHandler"/>
</security:http>
<security:http use-expressions="true" auto-config="false" pattern="/rcd/associate/*" entry-point-ref="http403ForbiddenEntryPoint" access-denied-page="/accessdenied.action">
<security:intercept-url pattern="/saml/sso/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:custom-filter position="BASIC_AUTH_FILTER" ref="defaultBasicAuthFilter" />
<security:expression-handler ref="expressionHandler"/>
</security:http>
<bean id="http403ForbiddenEntryPoint"
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<bean id="expressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="permissionEvaluator" ref="customPermissionEvaluator" />
</bean>
<bean id="defaultBasicAuthFilter"
class="com.example.security.authentication.DefaultAuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="AuthenticationFailureHandler" ref="failureHandler"></property>
</bean>
<bean id="authProvider"
class="com.example.security.authentication.CustomAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="authProvider" />
</security:authentication-manager>
<bean id="userDetailsService" class="com.example.security.authorization.UserDetailsServiceImpl" />
<bean id="successRedirectHandler"
class="com.example.security.authentication.CustomAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/user1/user1LandingPage.action"/>
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/accessdenied.action"/>
</bean>
我们也配置了web.xml
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/spring-app-context.xml <!-- ,/WEB-INF/spring/security.xml -->
</param-value>
</context-param>
<servlet>
<servlet-name>example-dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all /example*.action requests to the example-dispatcher-servlet for handling -->
<servlet-mapping>
<servlet-name>example-dispatcher-servlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>/rcd/pages/index.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>com.example.HttpSessionListenerImpl</listener-class>
</listener>
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
我们使用的是 spring 3.1.3 和 spring security 3.1.3 在每个用户登录时,应创建新会话并相应地设置安全上下文。但它发生在我的情况下。我检查了调试我的应用程序,发现用户登录时没有创建新会话。可能是我在某个地方想念它。我在任何地方都找不到任何相关的解决方案。
在这方面的任何帮助将不胜感激。
谢谢。
【问题讨论】:
使用修复了这个问题 怎么样?请添加您的答案。 @Ebanath,您希望其他人帮助您,但没有分享解决方法,为什么? 【参考方案1】:对不起各位,虽然我当时和那个时候本身已经解决了这个问题,但我很久没有看这个问题了 -
我在元素中使用了 securityContextPersistenceFilter 并配置如下 -
<security:http>
<security:custom-filter before="SECURITY_CONTEXT_FILTER" ref="securityContextPersistenceFilter"/>
....
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name="forceEagerSessionCreation" value="true"></property>
<property name="securityContextRepository" ref="httpSessionSecurityContextRepository"/>
</bean>
<bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
<property name="allowSessionCreation" value="false" />
</bean>
【讨论】:
我也有类似的需求,可以看看我的问题***.com/questions/34269682/…以上是关于使用自定义 AbstractAuthenticationProcessingFilter 和自定义 CustomAuthenticationProvider 的身份验证无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章
使用自定义动画删除自定义 UIStoryboardSegue