본문으로 건너뛰기

2.3. 중복 로그인 막기

한 계정으로 여러 곳에서 동시에 로그인하는 것을 막는 기능입니다. 나중에 로그인한 쪽을 살리고 먼저 로그인해 있던 쪽을 로그아웃시킵니다.

이 기능은 설정만으로는 동작하지 않습니다. 제품은 누가 로그인했는지 알 수 없으므로, 애플리케이션이 로그인에 성공한 시점에 사용자 ID 를 알려 줘야 합니다. 그래서 설정과 소스 코드 추가가 모두 필요합니다.

설정

allowDuplicateLogin 의 기본값이 false 라 이 기능은 처음부터 켜져 있습니다. 아래 예제가 false 를 명시하는 것은 의도를 분명히 하기 위한 것이며, 넣지 않아도 같게 동작합니다.

나머지 항목은 중복 로그인을 찾았을 때 어떻게 처리할지를 정합니다.

중복 로그인을 허용해야 한다면 allowDuplicateLogintrue 를 넣습니다. 이때 duplicateLoginPolicy 는 무시되고 legacy 로 고정됩니다.

web.xml

<init-param>
<param-name>allowDuplicateLogin</param-name>
<param-value>false</param-value> {/* false 로 설정해야 중복 로그인 방지 기능 활성화 */}
</init-param>
<init-param>
<param-name>duplicateLoginPolicy</param-name>
<param-value>legacy</param-value> {/* legacy 가 default 이므로 별도로 설정하지 않아도 legacy 모드 */}
</init-param>
<init-param>
<param-name>invalidateDuplicateLogin</param-name>
<param-value>true</param-value> {/* true 로 설정해야 중복 로그인 감지 시 기존 세션을 자동으로 무효화 */}
</init-param>
<init-param>
<param-name>logoutUrl</param-name>
<param-value>/logout.jsp</param-value> {/* 중복 로그인 시 logout url 설정 */}
</init-param>

OpenmaruFilterConfiguration

@Configuration
public class OpenmaruFilterConfiguration implements WebMvcConfigurer {

@Bean
public FilterRegistrationBean getFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new InfinispanHotRodSessionFilter());
registrationBean.setOrder(Integer.MIN_VALUE);

...
// false 로 설정해야 중복 로그인 방지 기능 활성화
registrationBean.addInitParameter(Constants.ALLOW_DUPLICATE_LOGIN, "false");

// legacy 가 default 이므로 별도로 설정하지 않아도 legacy 모드
registrationBean.addInitParameter(Constants.DUPLICATE_LOGIN_POLICY, "legacy");

// true 로 설정해야 중복 로그인 감지 시 기존 세션을 자동으로 무효화
registrationBean.addInitParameter(Constants.INVALIDATE_DUPLICATE_LOGIN, "true");

// 중복 로그인 시 logout url 설정
registrationBean.addInitParameter(Constants.LOGOUT_URL, "/logout.jsp");
...

registrationBean.setUrlPatterns(Arrays.asList("/*"));
registrationBean.setDispatcherTypes(DispatcherType.ERROR, DispatcherType.INCLUDE, DispatcherType.FORWARD, DispatcherType.REQUEST);
return registrationBean;
}
...
}

소스 코드 추가

설정만으로는 부족한 이유가 여기 있습니다. 애플리케이션이 "이 사람이 로그인했다" 를 알려 줘야 제품이 같은 계정의 다른 로그인을 찾아낼 수 있습니다.

넣어야 하는 곳은 두 자리입니다.

  1. 로그인에 성공한 직후 — 항상 필요합니다
  2. 로그아웃 처리invalidateDuplicateLoginfalse 일 때만 필요합니다

로그인 성공 후

사용자 인증을 통과한 다음 줄에 아래를 추가합니다. [USER_ID] 자리에 그 사용자의 ID 를 넣습니다.

SessionLoginManager.getInstance().login(request, [USER_ID]);

로그아웃 및 세션 무효화

invalidateDuplicateLogin=true 인 경우 (자동 로그아웃 처리)

invalidateDuplicateLogintrue로 설정되어 있으면 중복 로그인 시 자동으로 로그아웃 처리를 수행합니다.

동작

1. 중복 로그인 감지 시 `SessionLoginManager.getInstance().logout()` 자동 호출
2. 세션 무효화(`session.invalidate()`)까지 자동 처리
3. 설정된 로그아웃 URL로 자동 리다이렉트 (logoutUrl 설정 시)

따라서 애플리케이션 코드에서 별도의 로그아웃 처리 코드를 작성할 필요가 없습니다.

invalidateDuplicateLogin=false 인 경우 (수동 로그아웃 처리)

invalidateDuplicateLoginfalse로 설정하면 중복 로그인이 감지되어도 시스템에서 자동으로 세션을 무효화하지 않습니다. 중복 로그인을 직접 체크 및 invalidate 해야 할 경우 활용할 수 있습니다.

동작

1. 중복 로그인 감지 시 기존 세션을 무효화하지 않음
2. 세션 정보를 세션 저장소에서 제거하지 않음 (loginRemove 호출 안함)
3. SessionLoginManager.logout() 호출하지 않음
4. session.invalidate() 호출하지 않음
5. 설정된 logoutUrl로 리다이렉트만 수행 (logoutUrl이 설정된 경우)

수동으로 로그아웃 처리를 해야 하는 경우 다음 코드를 사용합니다.

SessionLoginManager.getInstance().logout(request);

사용자 명시적 로그아웃 처리

사용자가 직접 로그아웃 버튼을 클릭하는 경우 다음과 같이 처리합니다.

// 로그아웃 처리 예제
public void doLogout(HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
// OPENMARU Cluster 로그아웃 처리
SessionLoginManager.getInstance().logout(request);

// 세션 무효화
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}

// 로그인 페이지로 리다이렉트
response.sendRedirect("/login.jsp");

} catch (Exception e) {
// 로그아웃 실패 시 에러 처리
log.error("로그아웃 처리 중 오류 발생", e);
throw e;
}
}
  • 사용자 명시적 로그아웃 시에는 반드시 SessionLoginManager.getInstance().logout(request) 호출 후 session.invalidate()를 호출해야 합니다.
  • invalidateDuplicateLogin=true로 설정하면 중복 로그인 시 자동 처리되므로 별도 코드가 필요하지 않습니다.