From 88807f6d70089534e4dae694744f8f1fc1d59b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=87=A4=E5=90=89?= Date: Sat, 19 Apr 2025 20:45:29 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=99=BB=E5=87=BA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/a8k/app/config/WebConfig.java | 20 ++ .../api/v1/app/setting/DeviceSettingControler.java | 1 + .../app/interceptor/RefreshAccessInterceptor.java | 27 ++ .../a8k/app/service/data/AppUserMgrService.java | 282 +++++++++++++-------- .../app/service/setting/AppSettingsMgrService.java | 5 + 5 files changed, 229 insertions(+), 106 deletions(-) create mode 100644 src/main/java/a8k/app/config/WebConfig.java create mode 100644 src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java diff --git a/src/main/java/a8k/app/config/WebConfig.java b/src/main/java/a8k/app/config/WebConfig.java new file mode 100644 index 0000000..f59c752 --- /dev/null +++ b/src/main/java/a8k/app/config/WebConfig.java @@ -0,0 +1,20 @@ +package a8k.app.config; + +import a8k.app.interceptor.RefreshAccessInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + private final RefreshAccessInterceptor refreshInterceptor; + + public WebConfig(RefreshAccessInterceptor refreshInterceptor) { + this.refreshInterceptor = refreshInterceptor; + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(refreshInterceptor).addPathPatterns("/api/**"); + } +} \ No newline at end of file diff --git a/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingControler.java b/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingControler.java index efa1c0a..c0f1b39 100644 --- a/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingControler.java +++ b/src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingControler.java @@ -1,5 +1,6 @@ package a8k.app.controler.api.v1.app.setting; +import a8k.app.service.data.AppUserMgrService; import a8k.app.type.exception.AppException; import a8k.app.type.ui.ApiRet; import a8k.app.dao.type.db.DeviceSetting; diff --git a/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java b/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java new file mode 100644 index 0000000..9843872 --- /dev/null +++ b/src/main/java/a8k/app/interceptor/RefreshAccessInterceptor.java @@ -0,0 +1,27 @@ +package a8k.app.interceptor; + +import a8k.app.service.data.AppUserMgrService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +/** + * Interceptor that refreshes the last-access timestamp on each HTTP request. + */ +@Component +public class RefreshAccessInterceptor implements HandlerInterceptor { + + private final AppUserMgrService userMgr; + + public RefreshAccessInterceptor(AppUserMgrService userMgr) { + this.userMgr = userMgr; + } + + @Override + public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) { + userMgr.recordAccess(); + return true; + } +} diff --git a/src/main/java/a8k/app/service/data/AppUserMgrService.java b/src/main/java/a8k/app/service/data/AppUserMgrService.java index 6d09445..10a6c0d 100644 --- a/src/main/java/a8k/app/service/data/AppUserMgrService.java +++ b/src/main/java/a8k/app/service/data/AppUserMgrService.java @@ -1,123 +1,193 @@ package a8k.app.service.data; import a8k.app.dao.AppUsrDao; +import a8k.app.dao.DeviceSettingDao; import a8k.app.dao.type.db.AppUser; +import a8k.app.dao.type.db.DeviceSetting; import a8k.app.hardware.type.A8kEcode; import a8k.app.type.exception.AppException; +import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; import org.slf4j.Logger; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.time.Duration; +import java.time.Instant; import java.util.List; @Component +@EnableScheduling //Enable scheduled tasks public class AppUserMgrService { - static Logger logger = org.slf4j.LoggerFactory.getLogger(AppUserMgrService.class); - - @Resource - AppUsrDao appUsrDao; - - AppUser loginUsr = null; - - - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - // EXT FUNC - // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - - public AppUser login(int id, String password) throws AppException { - var usr = appUsrDao.getUsrById(id); - if (usr == null) - throw new AppException(A8kEcode.USR_NOT_EXIT); - - if (!usr.password.equals(password)) { - throw new AppException(A8kEcode.USR_PASSWORD_ERROR); - } - loginUsr = usr; - return (usr); - } - - - public Void unlogin() { - loginUsr = null; - return null; - } - - - synchronized public AppUser getLoginUsr() { - return (loginUsr); - } - - - public List getUsrlist() { - return (appUsrDao.getAllUsr()); - } - - - public AppUser addUser(String account, String password, AppUser.UsrRole type) throws AppException { - var user = appUsrDao.getUsrByAccount(account); - if (user != null) { - throw new AppException(A8kEcode.USR_ALREADY_EXIST); - } - user = new AppUser(account, password, type); - appUsrDao.addUser(user); - return appUsrDao.getUsrByAccount(account); - } - - - public Void delUser(Integer id) { - appUsrDao.deleteUserById(id); - return null; - } - - public AppUser updateUsr(AppUser usr) { - appUsrDao.updateUser(usr); - return usr; - } - - public AppUser modifyUsrPwd(Integer id, String oldpasswd,String password) throws AppException { - var user = appUsrDao.getUsrById(id); - if (user == null) { - throw new AppException(A8kEcode.USR_NOT_EXIT); - } - - if(!user.password.equals(oldpasswd)){ - throw new AppException(A8kEcode.USR_OLD_PASSWORD_ERROR); - } - - if (password.isEmpty()) { - throw new AppException(A8kEcode.USR_PASSWORD_IS_EMPTY); - } - - user.password = password; - appUsrDao.updateUser(user); - return user; - } - - - public AppUser modifyUsrRole(Integer id, AppUser.UsrRole usrRole) throws AppException { - var user = appUsrDao.getUsrById(id); - if (user == null) { - throw new AppException(A8kEcode.USR_NOT_EXIT); - } - user.usrRole = usrRole; - appUsrDao.updateUser(user); - return user; - - } - - - public AppUser modifyUsrAccount(Integer id, String newaccount) throws AppException { - var user = appUsrDao.getUsrById(id); - if (user == null) { - throw new AppException(A8kEcode.USR_NOT_EXIT); - } - user.account = newaccount; - appUsrDao.updateUser(user); - return user; - - } - + static Logger logger = org.slf4j.LoggerFactory.getLogger(AppUserMgrService.class); + + /** + * current user + */ + @Resource + AppUsrDao appUsrDao; + @Resource + DeviceSettingDao deviceSettingDao; + + AppUser loginUsr = null; + + /** + * timestamp of last access + */ + private volatile Instant lastAccess; + + /** + * auto logout time out duration + */ + private volatile Duration autoLogoutTimeout; + + /** + * flag to enable auto logout + */ + private volatile boolean autoLogout; + + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // EXT FUNC + // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + /** + * load timeout and switch + */ + @PostConstruct + public void init() { + DeviceSetting deviceSetting = deviceSettingDao.get(); + int minutes = deviceSetting.getAutoLogoutTimeout(); + this.autoLogoutTimeout = Duration.ofMinutes(minutes); + boolean autoLogout = deviceSetting.getAutoLogout(); + this.autoLogout = autoLogout; + logger.debug("initialized autoLogout={}, timeout={} minutes", autoLogout, minutes); + } + + + public AppUser login(int id, String password) throws AppException { + var usr = appUsrDao.getUsrById(id); + if (usr == null) + throw new AppException(A8kEcode.USR_NOT_EXIT); + + if (!usr.password.equals(password)) { + throw new AppException(A8kEcode.USR_PASSWORD_ERROR); + } + loginUsr = usr; + return (usr); + } + + + public Void unlogin() { + loginUsr = null; + return null; + } + + + /** + * refresh lastAccess on each intercepted request + */ + public synchronized void recordAccess() { + if (loginUsr != null) { + this.lastAccess = Instant.now(); + } + } + + public synchronized void updateAutoLogout(boolean autoLogout) { + this.autoLogout = autoLogout; + logger.debug("updated cache autoLogout:{}", autoLogout); + } + + public synchronized void updateAutoLogoutTimeout(int autoLogoutTimeout) { + this.autoLogoutTimeout = Duration.ofMinutes(autoLogoutTimeout); + logger.debug("updated cache autoLogoutTimeout {} minutes", autoLogoutTimeout); + } + + + synchronized public AppUser getLoginUsr() { + return (loginUsr); + } + + + public List getUsrlist() { + return (appUsrDao.getAllUsr()); + } + + + public AppUser addUser(String account, String password, AppUser.UsrRole type) throws AppException { + var user = appUsrDao.getUsrByAccount(account); + if (user != null) { + throw new AppException(A8kEcode.USR_ALREADY_EXIST); + } + user = new AppUser(account, password, type); + appUsrDao.addUser(user); + return appUsrDao.getUsrByAccount(account); + } + + + public Void delUser(Integer id) { + appUsrDao.deleteUserById(id); + return null; + } + + public AppUser updateUsr(AppUser usr) { + appUsrDao.updateUser(usr); + return usr; + } + + public AppUser modifyUsrPwd(Integer id, String oldpasswd, String password) throws AppException { + var user = appUsrDao.getUsrById(id); + if (user == null) { + throw new AppException(A8kEcode.USR_NOT_EXIT); + } + + if (!user.password.equals(oldpasswd)) { + throw new AppException(A8kEcode.USR_OLD_PASSWORD_ERROR); + } + + if (password.isEmpty()) { + throw new AppException(A8kEcode.USR_PASSWORD_IS_EMPTY); + } + + user.password = password; + appUsrDao.updateUser(user); + return user; + } + + + public AppUser modifyUsrRole(Integer id, AppUser.UsrRole usrRole) throws AppException { + var user = appUsrDao.getUsrById(id); + if (user == null) { + throw new AppException(A8kEcode.USR_NOT_EXIT); + } + user.usrRole = usrRole; + appUsrDao.updateUser(user); + return user; + + } + + + public AppUser modifyUsrAccount(Integer id, String newaccount) throws AppException { + var user = appUsrDao.getUsrById(id); + if (user == null) { + throw new AppException(A8kEcode.USR_NOT_EXIT); + } + user.account = newaccount; + appUsrDao.updateUser(user); + return user; + + } + + @Scheduled(fixedDelay = 60_000) + public void autoLogoutTask() { + if (!autoLogout || loginUsr == null) { + return; + } + if (Duration.between(lastAccess, Instant.now()).compareTo(autoLogoutTimeout) >= 0) { + logger.info("auto logout user {} after {} minutes inactivity", loginUsr.account, autoLogoutTimeout.toMinutes()); + unlogin(); + } + } } diff --git a/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java b/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java index 8f03735..af64911 100644 --- a/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java +++ b/src/main/java/a8k/app/service/setting/AppSettingsMgrService.java @@ -1,5 +1,6 @@ package a8k.app.service.setting; +import a8k.app.service.data.AppUserMgrService; import a8k.app.type.exception.AppException; import a8k.app.dao.DeviceSettingDao; import a8k.app.dao.LISSettingDao; @@ -16,6 +17,8 @@ import org.springframework.stereotype.Component; @Component public class AppSettingsMgrService { Logger logger = org.slf4j.LoggerFactory.getLogger(AppSettingsMgrService.class); + @Resource + AppUserMgrService appUserMgrService; @Resource DeviceSettingDao deviceSettingDao; @@ -61,12 +64,14 @@ public class AppSettingsMgrService { DeviceSetting setting = deviceSettingDao.get(); setting.autoLogoutTimeout = val; deviceSettingDao.update(setting); + appUserMgrService.updateAutoLogoutTimeout(val); } public void setAutoLogout(Boolean val) { DeviceSetting setting = deviceSettingDao.get(); setting.autoLogout = val; deviceSettingDao.update(setting); + appUserMgrService.updateAutoLogout(val); }