我已经尝试了整整一天,让我的定制身份验证失败处理程序与Spring 3.1.3工作。
我认为这是正确配置
<http use-expressions="true" disable-url-rewriting="true">
<intercept-url pattern="/rest/login" access="permitAll" />
<intercept-url pattern="/rest/**" access="isAuthenticated()" />
<intercept-url pattern="/index.html" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />
<intercept-url pattern="/**" access="denyAll" />
<form-login username-parameter="user" password-parameter="pass" login-page="/rest/login"
authentication-failure-handler-ref="authenticationFailureHandler" />
</http>
<beans:bean id="authenticationFailureHandler" class="LoginFailureHandler" />
我实现这个
public class LoginFailureHandler implements AuthenticationFailureHandler {
private static final Logger log = LoggerFactory.getLogger(LoginFailureHandler.class);
public LoginFailureHandler() {
log.debug("I am");
}
@Autowired
private ObjectMapper customObjectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
log.debug("invalid login");
User user = new User();
user.setUsername("invalid");
try (OutputStream out = response.getOutputStream()) {
customObjectMapper.writeValue(out, user);
}
}
}
在我看到控制台
2013-04-11 14:52:29,478 DEBUG LoginFailureHandler - I am
因此,它被装载。
随着错误的用户名或passwort,当BadCredentialsException被抛出,我没有看到无效的登录。
该方法onAuthenticationFailure是永远不会被调用。
取而代之的是服务到/ REST /登录一次又一次地将浏览器重定向...
编辑
2013-04-11 15:47:26,411 DEBUG de.pentos.spring.LoginController - Incomming login chuck.norris, norris
2013-04-11 15:47:26,412 DEBUG o.s.s.a.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2013-04-11 15:47:26,415 DEBUG o.s.s.a.d.DaoAuthenticationProvider - Authentication failed: password does not match stored value
2013-04-11 15:47:26,416 DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,419 DEBUG o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,419 DEBUG o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from handler [public de.pentos.spring.User de.pentos.spring.LoginController.login(de.pentos.spring.User)]: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2013-04-11 15:47:26,426 DEBUG o.s.web.servlet.DispatcherServlet - Could not complete request
org.springframework.security.authentication.BadCredentialsException: Bad credentials
这发生在调试模式
哪里是我的错?
从你连接我想你已经在执行登录过程中犯了一个错误日志判断。 我不能绝对肯定,但我猜你打电话ProviderManager.authenticate()
在你LoginController
。 该方法将引发BadCredentialsException
导致Spring MVC中的异常处理机制踢,这当然没有关于知识AuthenticationFailureHandler
配置为春季安全。
从登录控制器通常应该只是成为一个简单的登录表单action="j_spring_security_check" method="post"
。 当用户提交该形式中,配置的安全过滤器(即UsernamePasswordAuthenticationFilter
),该请求和处理认证截距。 你不必以实现一个控制器的方法自己说的逻辑。
回复您的评论:
你使用ProviderManager
(它的自动装配的实现AuthenticationManager
接口)。 你犯的错误是,试图重写已经实施和权威性过滤器彻底测试的逻辑。 这是坏的本身,但即使是在一个错误的方式来完成。 您可以选择从复杂的逻辑,短短的几行,而其中你忘记例如调用会话策略,其他的事情(以防止会话固定攻击,以及处理并发会话)。 原来实现调用AuthenticationFailureHandler
还有,你也忘了在你的方法,这是你原来的问题是关于这个问题的的真正原因。
所以,你最终用一个未经考验的,脆弱的解决方案,而不是与框架很好地整合利用其roboustness和满负荷生产。 正如我所说的,你在你的答案张贴的配置是一个明确的改善,因为它使用的身份验证框架提供的过滤器。 记住,配置和删除LoginController.login()
它不会被通过反正发送到信息请求调用/rest/login
。
一个更根本的问题是,如果它真的如果实现RESTful服务使用会话和基于表单的登录机制,一个好的解决方案。 (在基于表单登录我的意思是客户端的任何格式发送一次其凭据,然后被用在后续请求中有状态会话认证)。通过REST服务它更普遍把一切都无状态,并重新验证每个新的请求由HTTP头中携带的信息。
这是与在安全应用-context.xml中的顺序有问题。
如果我先定义所有的豆子,然后所有其余它的工作原理。 我尝试了很多,所以不要怀疑,它现在看起来有点不同,那么在这个问题
<beans:bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/rest/login" />
</beans:bean>
<beans:bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="filterProcessesUrl" value="/rest/login" />
<beans:property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
<beans:property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
</beans:bean>
<beans:bean id="authenticationSuccessHandler" class="de.pentos.spring.LoginSuccessHandler" />
<beans:bean id="authenticationFailureHandler" class="de.pentos.spring.LoginFailureHandler" />
<http use-expressions="true" disable-url-rewriting="true" entry-point-ref="authenticationProcessingFilterEntryPoint"
create-session="ifRequired">
<intercept-url pattern="/rest/login" access="permitAll" />
<intercept-url pattern="/rest/**" access="isAuthenticated()" />
<intercept-url pattern="/index.html" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />
<intercept-url pattern="/**" access="denyAll" />
<custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="chuck.norris" password="cnorris" authorities="ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
不看对我不好。 你尝试用你的IDE的调试模式?
你有没有看到这样的事情在你的日志:
Authentication request failed: ...
Updated SecurityContextHolder to contain null Authentication
Delegating to authentication failure handler ...
通常在你的情况UsernamePasswordAuthenticationFilter:只有在认证在认证过滤器的一个完成的AuthenticationFailureHandler将自动被调用。
(在你的要求看),你不需要自定义AuthenticationFailureHandler作为春天的默认SimpleUrlAuthenticationFailureHandler和正确实施的AuthenticationProvider应该服务宗旨。
<form-login login-page="/login" login-processing-url="/do/login" authentication- failure-url ="/login?authfailed=true" authentication-success-handler-ref ="customAuthenticationSuccessHandler"/>
如果你已经处理好了在身份验证提供例外:
采样逻辑:
String loginUsername = (String) authentication.getPrincipal();
if (loginUsername == null)
throw new UsernameNotFoundException("User not found");
String loginPassword = (String) authentication.getCredentials();
User user = getUserByUsername(loginUsername);
UserPassword password = getPassword(user.getId());
if (!password.matches(loginPassword)) {
throw new BadCredentialsException("Invalid password.");
}
如果我们想扔在客户端界面中反映出来的异常,在JSP中添加以下scriplet响应认证失败-URL =“/登录?authfailed =真”
<%
Exception error = (Exception) request.getSession().getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
if (error != null)
out.write(error.getMessage());
%>