Skip to content

Commit

Permalink
fix: correct device information update during account switch (#6483)
Browse files Browse the repository at this point in the history
#### 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
修复切换账号登录时设备信息更新不正确的问题
```
  • Loading branch information
guqing authored Aug 22, 2024
1 parent f9615d0 commit 87368df
Showing 1 changed file with 34 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class DeviceServiceImpl implements DeviceService {

@Override
public Mono<Void> loginSuccess(ServerWebExchange exchange, Authentication authentication) {
return updateExistingDevice(exchange)
return updateExistingDevice(exchange, authentication)
.switchIfEmpty(createDevice(exchange, authentication)
.flatMap(client::create)
.doOnNext(device -> {
Expand All @@ -61,10 +61,7 @@ public Mono<Void> changeSessionId(ServerWebExchange exchange) {
.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))
Expand All @@ -78,48 +75,52 @@ public Mono<Void> changeSessionId(ServerWebExchange exchange) {
});
}

private Mono<Device> updateWithRetry(String deviceId,
private Mono<Device> updateWithRetry(String deviceId, String username,
Function<Device, Mono<Device>> updateFunction) {
return Mono.defer(() -> client.fetch(Device.class, deviceId)
.filter(device -> device.getSpec().getPrincipalName().equals(username))
.flatMap(updateFunction)
.flatMap(client::update)
)
.retryWhen(Retry.backoff(8, Duration.ofMillis(100))
.filter(OptimisticLockingFailureException.class::isInstance));
}

private Mono<Device> updateExistingDevice(ServerWebExchange exchange) {
private Mono<Device> 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
Expand Down

0 comments on commit 87368df

Please sign in to comment.