From 87368df18a60829ce403373c73fae3c1029e51d8 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:02:56 +0800 Subject: [PATCH] fix: correct device information update during account switch (#6483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind bug /area core /milestone 2.19.x #### What this PR does / why we need it: 修复切换账号登录时设备信息更新不正确的问题 原因: 1. 使用 admin 账号登录,此时会记录 device_id 的 cookie 2. 退出登录,device_id 会保留在 cookie 中并随着新账号带到服务端 3. 服务端根据 device_id 查询当前设备是否有对应的记录,但是没有校验用户名是否与当前登陆的一致然后就去更新登录时间 4. 正确的处理是校验 device_id 是否有与之对应的记录并且用户名相同,如果不相同则认为是新设备重新生成 device_id **how to test it?** 1. 先清理 cookie 然后使用一个账号登录 2. 退出登陆并切换新账号登录 3. 检查新登录的账号的设备信息是否正确 #### Does this PR introduce a user-facing change? ```release-note 修复切换账号登录时设备信息更新不正确的问题 ``` --- .../security/device/DeviceServiceImpl.java | 67 ++++++++++--------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/application/src/main/java/run/halo/app/security/device/DeviceServiceImpl.java b/application/src/main/java/run/halo/app/security/device/DeviceServiceImpl.java index c2ad61f17..001265a79 100644 --- a/application/src/main/java/run/halo/app/security/device/DeviceServiceImpl.java +++ b/application/src/main/java/run/halo/app/security/device/DeviceServiceImpl.java @@ -40,7 +40,7 @@ public class DeviceServiceImpl implements DeviceService { @Override public Mono loginSuccess(ServerWebExchange exchange, Authentication authentication) { - return updateExistingDevice(exchange) + return updateExistingDevice(exchange, authentication) .switchIfEmpty(createDevice(exchange, authentication) .flatMap(client::create) .doOnNext(device -> { @@ -61,10 +61,7 @@ public class DeviceServiceImpl implements DeviceService { .map(context -> context.getAuthentication().getName()) .flatMap(username -> { var deviceId = deviceIdCookie.getValue(); - return updateWithRetry(deviceId, device -> { - if (!device.getSpec().getPrincipalName().equals(username)) { - return Mono.empty(); - } + return updateWithRetry(deviceId, username, device -> { var oldSessionId = device.getSpec().getSessionId(); return exchange.getSession() .filter(session -> !session.getId().equals(oldSessionId)) @@ -78,9 +75,10 @@ public class DeviceServiceImpl implements DeviceService { }); } - private Mono updateWithRetry(String deviceId, + private Mono updateWithRetry(String deviceId, String username, Function> updateFunction) { return Mono.defer(() -> client.fetch(Device.class, deviceId) + .filter(device -> device.getSpec().getPrincipalName().equals(username)) .flatMap(updateFunction) .flatMap(client::update) ) @@ -88,38 +86,41 @@ public class DeviceServiceImpl implements DeviceService { .filter(OptimisticLockingFailureException.class::isInstance)); } - private Mono updateExistingDevice(ServerWebExchange exchange) { + private Mono updateExistingDevice(ServerWebExchange exchange, + Authentication authentication) { var deviceIdCookie = deviceCookieResolver.resolveCookie(exchange); if (deviceIdCookie == null) { return Mono.empty(); } - return updateWithRetry(deviceIdCookie.getValue(), (Device existingDevice) -> { - var sessionId = existingDevice.getSpec().getSessionId(); - return exchange.getSession() - .flatMap(session -> { - var userAgent = - exchange.getRequest().getHeaders().getFirst(HttpHeaders.USER_AGENT); - var deviceUa = existingDevice.getSpec().getUserAgent(); - if (!StringUtils.equals(deviceUa, userAgent)) { - // User agent changed, create a new device - return Mono.empty(); - } - return Mono.just(session); - }) - .flatMap(session -> { - if (session.getId().equals(sessionId)) { + var principalName = authentication.getName(); + return updateWithRetry(deviceIdCookie.getValue(), principalName, + (Device existingDevice) -> { + var sessionId = existingDevice.getSpec().getSessionId(); + return exchange.getSession() + .flatMap(session -> { + var userAgent = + exchange.getRequest().getHeaders().getFirst(HttpHeaders.USER_AGENT); + var deviceUa = existingDevice.getSpec().getUserAgent(); + if (!StringUtils.equals(deviceUa, userAgent)) { + // User agent changed, create a new device + return Mono.empty(); + } return Mono.just(session); - } - return sessionRepository.deleteById(sessionId).thenReturn(session); - }) - .map(session -> { - existingDevice.getSpec().setSessionId(session.getId()); - existingDevice.getSpec().setLastAccessedTime(session.getLastAccessTime()); - existingDevice.getSpec().setLastAuthenticatedTime(Instant.now()); - return existingDevice; - }) - .flatMap(this::removeRememberMeToken); - }); + }) + .flatMap(session -> { + if (session.getId().equals(sessionId)) { + return Mono.just(session); + } + return sessionRepository.deleteById(sessionId).thenReturn(session); + }) + .map(session -> { + existingDevice.getSpec().setSessionId(session.getId()); + existingDevice.getSpec().setLastAccessedTime(session.getLastAccessTime()); + existingDevice.getSpec().setLastAuthenticatedTime(Instant.now()); + return existingDevice; + }) + .flatMap(this::removeRememberMeToken); + }); } @Override