春季安全登录/注销登录
我试图找到一种方法来保持数据库记录,当用户通过spring-security进行身份验证时。同样,当他们注销或超时时,我想在那段时间更新该记录。我一直试图使用AuthenticationSuccessHandler进行登录处理,并且LogoutSuccessHandler用于登出。但是,当我使用它时,那么我的URL在重定向后似乎会中断。春季安全登录/注销登录
这是我到目前为止有:
@Component
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler {
public MyLoginSuccessHandler() {
super();
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("Logged In User " + (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal());
}
}
和陷阱注销事件:
@Component
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
public MyLogoutSuccessHandler() {
super();
}
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
System.out.println("Logged OUT User " + (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal());
}
}
而且配置我的安全性,例如:
@Configuration
@EnableWebMvcSecurity
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private MyLogoutSuccessHandler myLogoutSuccessHandler;
@Autowired
private MyLoginSuccessHandler myLoginSuccessHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().failureUrl("/login?error")
.successHandler(myLoginSuccessHandler)
.defaultSuccessUrl("/")
.loginPage("/login")
.permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll();
http
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?expired")
.maxSessionsPreventsLogin(true)
.and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/");
http
.authorizeRequests().anyRequest().authenticated();
http
.logout()
.logoutSuccessHandler(myLogoutSuccessHandler)
.logoutSuccessUrl("/");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(customUserDetailsService).passwordEncoder(encoder);
}
}
如果我在.successHandler之前放置.defaultSuccessUrl("/")
,然后处理程序被调用,但页面重定向不会发生,登录会导致/ login的空白页面。类似的/注销。
任何人都可以看到的问题是什么在这里
UPDATE: 我增加了执行器和我自己的ApplicationListener:
@Component
public class LoginListener implements ApplicationListener<AuthenticationSuccessEvent> {
private static final Logger LOG = LoggerFactory.getLogger(LoginListener.class);
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
UserDetails ud = (UserDetails) event.getAuthentication().getPrincipal();
LOG.info("User " + ud.getUsername() + " logged in successfully");
}
}
现在,当登录时,我得到的消息: 2014-11-06 10:10:55.923 INFO 90807 --- [nio-9001-exec-7] osbaaudit.listener.AuditListener:AuditEvent [timestamp = Thu Nov 06 10:10:55 MST 2014,principal = admin, type = AUTHENTICATION_SUCCESS,data = {details = org.springframework.security.web.authentication.WebAuthenticat ionDetails @ 21a2c:RemoteIpAddress:0:0:0:0:0:0:0:1; SessionId:64320375B40CF959936E86F4D1F2973C}]
而且我看到执行的代码。所以如果我可以到达AuditEvent,我将拥有我的日志记录的IP和时间戳。对于注销,我想尽自己的LogoutHandler:
@Component
public class MyLogoutHandler implements LogoutHandler {
private static final Logger LOG = LoggerFactory.getLogger(MyLogoutHandler.class);
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
User user = (User) authentication.getPrincipal();
LOG.info("User " + user.getUsername() + " logged OUT successfully");
}
}
我也试图通过监听处理:
@Component
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent> {
private static final Logger LOG = LoggerFactory.getLogger(LogoutListener.class);
@Override
public void onApplicationEvent(SessionDestroyedEvent event) {
List<SecurityContext> lstSecurityContext = event.getSecurityContexts();
UserDetails ud;
for (SecurityContext securityContext : lstSecurityContext)
{
ud = (UserDetails) securityContext.getAuthentication().getPrincipal();
LOG.debug("User " + ud.getUsername() + " logged OUT successfully");
}
}
}
没有这些电话都是以往任何时候都调用。在拨打电话时也不会有任何消息传送到控制台。我有一个在
public void sessionDestroyed(HttpSessionEvent arg0) {
totalActiveSessions--;
System.out.println("sessionDestroyed - deduct one session from counter: " + totalActiveSessions);
}
输出一条消息和一个被称为HttpSessionListener类,所以我肯定注销发生。
我曾与注销后做额外的东西了同样的问题,并解决它通过以下方式:
- 我用的,就像你在你的更新方法,一个
ApplicationListener<SessionDestroyedEvent>
。 -
但是,您还必须将
HttpSessionEventPublisher
添加到部署描述符中。原因描述在this页面。简而言之:
会话销毁事件是Java EEHttpSessionEvent
,发生在Spring环境之外。你可以用Java EEHttpSessionListener
来捕捉它们。但是如果你想访问Spring相关的bean - f.e.春天的身份验证 - 那么你必须添加HttpSessionEventPublisher
- 它转换的Java EE的事件将弹簧活动:<listener> <listener-class> org.springframework.security.web.session.HttpSessionEventPublisher </listener-class> </listener>
在这之后,你可以赶上SessionDestroyedEvent
这样的:
@Component
public class AuthenticationApplicationListener {
@EventListener
public void handleSessionDestroyedEvent(SessionDestroyedEvent event) {
List<SecurityContext> lstSecurityContext = event.getSecurityContexts();
for (SecurityContext securityContext : lstSecurityContext) {
//Try to find out, if this event is caused by a logout,
//This is true, when the old session has been an authenticated one.
Authentication auth = securityContext.getAuthentication();
if (auth == null ||
!auth.isAuthenticated() ||
auth instanceof AnonymousAuthenticationToken) {
return;
}
//do something
}
}
与成功处理程序相比,此方法具有一些优势:
- 它也在工作,当你使用程序注销(f.e.通过
HttpServletRequest.logout()
) - 当您通过url使用注销时,它不会中断过滤器链。
也参见this answer
见[此](http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-auditing.html)部的参考指南。添加'spring-boot-starter-actuator'依赖并实现你自己的'AuditEventRepository'。您需要额外的'LogoutHandler'来发布注销的审计事件(我怀疑),但这是您所需要的。 – 2014-11-06 07:02:49
好主意。或者只是听'AuthenticationSuccessEvent'。但我不知道是否有注销事件。 – 2014-11-06 07:08:34
@DaveSyer目前没有。见[gh-1836](https://github.com/spring-projects/spring-boot/issues/1836)和[SEC-2680](https://jira.spring.io/browse/SEC-2680) 。 – 2014-11-06 11:54:00