diff --git a/api/src/main/java/run/halo/app/event/user/UserLoginEvent.java b/api/src/main/java/run/halo/app/event/user/UserLoginEvent.java new file mode 100644 index 000000000..51a42f21a --- /dev/null +++ b/api/src/main/java/run/halo/app/event/user/UserLoginEvent.java @@ -0,0 +1,23 @@ +package run.halo.app.event.user; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; +import run.halo.app.core.extension.User; +import run.halo.app.plugin.SharedEvent; + +/** + * User login event. + * + * @author lywq + **/ +@SharedEvent +public class UserLoginEvent extends ApplicationEvent { + + @Getter + private final User user; + + public UserLoginEvent(Object source, User user) { + super(source); + this.user = user; + } +} diff --git a/api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java b/api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java new file mode 100644 index 000000000..c220d520e --- /dev/null +++ b/api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java @@ -0,0 +1,23 @@ +package run.halo.app.event.user; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; +import run.halo.app.core.extension.User; +import run.halo.app.plugin.SharedEvent; + +/** + * User logout event. + * + * @author lywq + **/ +@SharedEvent +public class UserLogoutEvent extends ApplicationEvent { + + @Getter + private final User user; + + public UserLogoutEvent(Object source, User user) { + super(source); + this.user = user; + } +} diff --git a/application/src/main/java/run/halo/app/core/user/service/UserLoginOrLogoutProcessing.java b/application/src/main/java/run/halo/app/core/user/service/UserLoginOrLogoutProcessing.java new file mode 100644 index 000000000..9a6c1a79a --- /dev/null +++ b/application/src/main/java/run/halo/app/core/user/service/UserLoginOrLogoutProcessing.java @@ -0,0 +1,38 @@ +package run.halo.app.core.user.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; +import run.halo.app.event.user.UserLoginEvent; +import run.halo.app.event.user.UserLogoutEvent; + +/** + * User login or logout processing service. + * + * @author lywq + **/ +@Component +@RequiredArgsConstructor +public class UserLoginOrLogoutProcessing { + + private final UserService userService; + private final ApplicationEventPublisher eventPublisher; + + public Mono loginProcessing(String username) { + return userService.getUser(username) + .doOnNext(user -> { + eventPublisher.publishEvent(new UserLoginEvent(this, user)); + }) + .then(); + } + + public Mono logoutProcessing(String username) { + return userService.getUser(username) + .doOnNext(user -> { + eventPublisher.publishEvent(new UserLogoutEvent(this, user)); + }) + .then(); + } + +} diff --git a/application/src/main/java/run/halo/app/security/LoginHandlerEnhancerImpl.java b/application/src/main/java/run/halo/app/security/LoginHandlerEnhancerImpl.java index b23ed667e..9706b5645 100644 --- a/application/src/main/java/run/halo/app/security/LoginHandlerEnhancerImpl.java +++ b/application/src/main/java/run/halo/app/security/LoginHandlerEnhancerImpl.java @@ -6,6 +6,7 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import run.halo.app.core.user.service.UserLoginOrLogoutProcessing; import run.halo.app.security.authentication.oauth2.OAuth2LoginHandlerEnhancer; import run.halo.app.security.authentication.rememberme.RememberMeRequestCache; import run.halo.app.security.authentication.rememberme.RememberMeServices; @@ -32,6 +33,8 @@ public class LoginHandlerEnhancerImpl implements LoginHandlerEnhancer { private final OAuth2LoginHandlerEnhancer oauth2LoginHandlerEnhancer; + private final UserLoginOrLogoutProcessing userLoginOrLogoutProcessing; + @Override public Mono onLoginSuccess(ServerWebExchange exchange, Authentication successfulAuthentication) { @@ -39,7 +42,8 @@ public class LoginHandlerEnhancerImpl implements LoginHandlerEnhancer { rememberMeServices.loginSuccess(exchange, successfulAuthentication), deviceService.loginSuccess(exchange, successfulAuthentication), rememberMeRequestCache.removeRememberMe(exchange), - oauth2LoginHandlerEnhancer.loginSuccess(exchange, successfulAuthentication) + oauth2LoginHandlerEnhancer.loginSuccess(exchange, successfulAuthentication), + userLoginOrLogoutProcessing.loginProcessing(successfulAuthentication.getName()) ); } diff --git a/application/src/main/java/run/halo/app/security/LogoutSecurityConfigurer.java b/application/src/main/java/run/halo/app/security/LogoutSecurityConfigurer.java index 8917754a3..13bf8c168 100644 --- a/application/src/main/java/run/halo/app/security/LogoutSecurityConfigurer.java +++ b/application/src/main/java/run/halo/app/security/LogoutSecurityConfigurer.java @@ -30,6 +30,7 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; +import run.halo.app.core.user.service.UserLoginOrLogoutProcessing; import run.halo.app.core.user.service.UserService; import run.halo.app.infra.actuator.GlobalInfoService; import run.halo.app.security.authentication.SecurityConfigurer; @@ -45,6 +46,8 @@ public class LogoutSecurityConfigurer implements SecurityConfigurer { private final ApplicationContext applicationContext; + private final UserLoginOrLogoutProcessing userLoginOrLogoutProcessing; + private final ServerRequestCache serverRequestCache = new HaloServerRequestCache(); @Override @@ -108,6 +111,7 @@ public class LogoutSecurityConfigurer implements SecurityConfigurer { Authentication authentication) { return logoutHandler.logout(exchange, authentication) .then(rememberMeServices.loginFail(exchange.getExchange())) + .then(userLoginOrLogoutProcessing.logoutProcessing(authentication.getName())) .then(ignoringMediaTypeAll(MediaType.APPLICATION_JSON) .matches(exchange.getExchange()) .filter(ServerWebExchangeMatcher.MatchResult::isMatch)