我有登录成功和重定向到页面的奇怪问题。
下面是我的弹簧安全配置。
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.hst**" access="anonymous or authenticated" />
<intercept-url pattern="/**/*.hst" access="authenticated" />
<form-login login-page="/login.hst"
authentication-failure-url="/login.hst?error=true"
authentication-success-handler-ref="loginSucessHandler" />
<logout invalidate-session="true" logout-success-url="/home.hst"
logout-url="/logout.hst" />
<remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
LoginSuessHandler类:
@Service
public class LoginSucessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
...
super.setUseReferer(true);
super.onAuthenticationSuccess(request, response, authentication);
}
}
现在成功重定向到请求页面的问题。如果我直接引用任何安全网址spring将我重定向到登录页面并成功登录到原始请求的链接。 但是,如果用户之前选择了remember-me然后关闭浏览器并且现在请求直接URL,那么这不起作用,他正在进行适当的身份验证,而不是将他重定向到请求的页面重定向到/。我检查了日志和一些弹簧源代码,发现它无法确定目标网址。
我试图设置引用但引用值为null。但有一件奇怪的事我注意到,在spring安全配置中,如果我从remember-me配置中删除authentication-success-handler,那么它可以工作。
<remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
无法找出问题。是身份验证成功处理程序实现需要不同的表单登录和记住我吗?
答案 0 :(得分:14)
记住我与表单登录的不同之处在于,在用户提出的实际请求期间进行身份验证。对于表单登录,必须首先将用户重定向到登录页面,提交登录表单,然后将其重定向到原始目标(通常在会话中缓存)。因此,表单登录需要重定向,而记住我不需要。通过记住我的请求,可以对用户进行身份验证,并允许请求继续进行而无需任何干预。
AuthenticationSuccessHandler
的主要目的是在身份验证后控制导航流程,因此您通常不会使用记住我的导航流程。使用SavedRequestAwareAuthenticationSuccessHandler
不是一个好主意,因为没有可用的已保存请求。如果没有已保存的请求,则默认情况下它将执行重定向到您观察到的“/”。
如果你想要的是在记住我的登录过程中添加一些功能,那么你可以直接实现AuthenticationSuccessHandler
接口,而无需执行重定向或转发。正如我上面所解释的,您不能对表单登录使用相同的实现,因为当前请求是提交登录表单(通常是URL j_spring_security_check
),而不是对您的URL的请求应用。因此,您需要重定向表单登录。
答案 1 :(得分:13)
您宁愿使用ApplicationListener
并查找事件InteractiveAuthenticationSuccessEvent
。
InteractiveAuthenticationSuccessEvent
有一个属性generatedBy
,它将是过滤器,即UsernamePasswordAuthenticationFilter
(表单登录)和RememberMeAuthenticationFilter
(记住登录)
@Component
class AuthenticationApplicationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
@Override
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
//do something
}
}
AuthenticationSuccessHandler
的自定义实现会导致问题。看看RememberMeAuthenticationFilter
中的流程。如果使用successHandler
,则绕过过滤器链
答案 2 :(得分:2)
使用AuthenticationSuccessHandler
不起作用。如另一个答案所述,弹簧安全过滤器链将被绕过!
什么有效,是使用ApplicationListener
- 另一个答案也提出。但要了解一下,如果您的用户通过记住我进行身份验证,那么使用InteractiveAuthenticationSuccessEvent.getGeneratedBy()
的想法就无效了:getGeneratedBy
会返回Class<T>
,这意味着通用。因此,在运行时,如果T
是RememberMeAuthenticationFilter
,则无法找到。
什么对我有用:使用InteractiveAuthenticationSuccessEvent.getAuthentication()
。
这里有一个例子(顺便说一句:@EventListener
从Spring Security 4.2开始使用 - 如果您使用的是早期版本,请通过实现ApplicationListener<InteractiveAuthenticationSuccessEvent>
来执行以下操作:
@Component
public class AuthenticationApplicationListener {
@EventListener
public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
if (RememberMeAuthenticationToken.class.isAssignableFrom(event.getAuthentication().getClass())) {
.... do some stuff
}
}
}
答案 3 :(得分:1)
您应该为登录表单和记住我实现不同的身份验证成功处理程序。 如果要在remeber-me处理程序中执行重定向,可以使用SimpleUrlAuthenticationSuccessHandler并设置DefaultTargetUrl。
public class RememberMeAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// ...
super.setAlwaysUseDefaultTargetUrl(true);
super.setDefaultTargetUrl(request.getRequestURL().toString());
super.onAuthenticationSuccess(request, response, authentication);
}