Program Tip

(스프링 보안을 통해) 내 웹 애플리케이션에 로그인 한 모든 사용자 목록을 어떻게 가질 수 있습니까?

programtip 2020. 11. 24. 19:27
반응형

(스프링 보안을 통해) 내 웹 애플리케이션에 로그인 한 모든 사용자 목록을 어떻게 가질 수 있습니까?


웹 응용 프로그램에서 스프링 보안을 사용하고 있으며 이제 프로그램에 로그인 한 모든 사용자 목록을 갖고 싶습니다.

그 목록에 어떻게 액세스 할 수 있습니까? 이미 스프링 프레임 워크 내 어딘가에 보관되어 있지 않습니까? SecurityContextHolder 또는 SecurityContextRepository 처럼 ?


로그인 한 모든 사용자 목록에 액세스하려면 SessionRegistry 인스턴스를 Bean에 삽입해야합니다.

@Autowired
@Qualifier("sessionRegistry")
private SessionRegistry sessionRegistry;

그런 다음 injcted SessionRegistry를 사용하여 모든 주체 목록에 액세스 할 수 있습니다.

List<Object> principals = sessionRegistry.getAllPrincipals();

List<String> usersNamesList = new ArrayList<String>();

for (Object principal: principals) {
    if (principal instanceof User) {
        usersNamesList.add(((User) principal).getUsername());
    }
}

그러나 세션 레지스트리를 삽입하기 전에 spring-security.xml ( Spring Security 참조 문서의 Session Management 섹션 참조 ) 에서 세션 관리 부분을 정의해야하고 동시성 제어 섹션에서 세션 레지스트리 객체 ( session-registry- alias )를 삽입합니다.

    <security:http access-denied-page="/error403.jsp" use-expressions="true" auto-config="false">
        <security:session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true"> 
            <security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
        </security:session-management>

    ...
    </security:http>

JavaConfig에서는 다음과 같습니다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        // ...
        http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
    }
}

호출 코드는 다음과 같습니다.

public class UserController {
    @Autowired
    private SessionRegistry sessionRegistry;

    public void listLoggedInUsers() {
        final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();

        for(final Object principal : allPrincipals) {
            if(principal instanceof SecurityUser) {
                final SecurityUser user = (SecurityUser) principal;

                // Do something with user
                System.out.println(user);
            }
        }
    }
}

그 주 SecurityUser되는 구현 내 자신의 클래스입니다 UserDetails.


내가 틀렸다면 나를 고쳐주세요.

@Adam의 대답이 불완전 하다고 생각 합니다. 목록에서 이미 만료 된 세션이 다시 나타나는 것을 확인했습니다.

public class UserController {
    @Autowired
    private SessionRegistry sessionRegistry;

    public void listLoggedInUsers() {
        final List<Object> allPrincipals = sessionRegistry.getAllPrincipals();

        for (final Object principal : allPrincipals) {
            if (principal instanceof SecurityUser) {
                final SecurityUser user = (SecurityUser) principal;

                List<SessionInformation> activeUserSessions =
                        sessionRegistry.getAllSessions(principal,
                                /* includeExpiredSessions */ false); // Should not return null;

                if (!activeUserSessions.isEmpty()) {
                    // Do something with user
                    System.out.println(user);
                }
            }
        }
    }
}

도움이 되었기를 바랍니다.


나도 틀렸다면 나를 고쳐주세요.

@Adam과 @elysch의 대답이 불완전하다고 생각합니다. 리스너를 추가해야한다는 것을 알았습니다.

 servletContext.addListener(HttpSessionEventPublisher.class);

...에

public class AppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) {
  ...
servletContext.addListener(HttpSessionEventPublisher.class);
}

보안 구성 :

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        // ...
        http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());
    }

    @Bean
    public SessionRegistry sessionRegistry() {
        return new SessionRegistryImpl();
    }

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
}

그러면 현재 온라인 사용자를 얻을 수 있습니다!


SessionRegistry앞서 언급했듯이 주입해야 하며 다음과 같이 하나의 파이프 라인에서 수행 할 수 있습니다.

public List<UserDetails> findAllLoggedInUsers() {
    return sessionRegistry.getAllPrincipals()
            .stream()
            .filter(principal -> principal instanceof UserDetails)
            .map(UserDetails.class::cast)
            .collect(Collectors.toList());
}

@rolyanos 솔루션과 유사하게 나를 위해 항상 작동합니다.

-컨트롤러 용

@RequestMapping(value = "/admin")
public String admin(Map<String, Object> model) {

    if(sessionRegistry.getAllPrincipals().size() != 0) {
        logger.info("ACTIVE USER: " + sessionRegistry.getAllPrincipals().size());
        model.put("activeuser",  sessionRegistry.getAllPrincipals().size());
    }
    else
        logger.warn("EMPTY" );

    logger.debug(log_msg_a + " access ADMIN page. Access granted." + ANSI_RESET);
    return "admin";
}

-프런트 엔드 용

<tr th:each="activeuser, iterStat: ${activeuser}">
    <th><b>Active users: </b></th> <td align="center" th:text="${activeuser}"></td>
    </tr>

-봄 고백 용

@Bean
public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
}

@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher() {
    return new ServletListenerRegistrationBean<HttpSessionEventPublisher>(new HttpSessionEventPublisher());
}


@Override
protected void configure(HttpSecurity http) throws Exception {

    http.logout()
    .logoutSuccessUrl("/home")
    .logoutUrl("/logout")
    .invalidateHttpSession(true)
    .deleteCookies("JSESSIONID");


    http.authorizeRequests()
    .antMatchers("/", "/home")
    .permitAll()

    .antMatchers("/admin")
    .hasRole("ADMIN") 
    .anyRequest()
    .authenticated()

    .and()
    .formLogin()
    .loginPage("/home")
    .defaultSuccessUrl("/main")
    .permitAll()
    .and()
    .logout()
    .permitAll();

    http.sessionManagement().maximumSessions(1).sessionRegistry(sessionRegistry());

    http.authorizeRequests().antMatchers("/webjars/**").permitAll();

    http.exceptionHandling().accessDeniedPage("/403");
}

이 메모가 매우 중요하고 관련성이 있음을 발견했습니다.

"[21] 인증 후 리디렉션을 수행하는 메커니즘 (예 : 양식 로그인)에 의한 인증은 인증 요청 중에 필터가 호출되지 않으므로 SessionManagementFilter에 의해 감지되지 않습니다. 세션 관리 기능은 이들에서 별도로 처리되어야합니다. 케이스. "

https://docs.spring.io/spring-security/site/docs/3.1.x/reference/session-mgmt.html#d0e4399

Also, apparently a lot of people have troubles getting sessionRegistry.getAllPrincipals() returning something different from an empty array. In my case, I fixed it by adding the sessionAuthenticationStrategy to my custom authenticationFilter:

@Bean
public CustomUsernamePasswordAuthenticationFilter authenticationFilter() throws Exception {
...

  authenticationFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy());
}

@Bean
public SessionRegistry sessionRegistry() {
    return new SessionRegistryImpl();
}

//cf. https://stackoverflow.com/questions/32463022/sessionregistry-is-empty-when-i-use-concurrentsessioncontrolauthenticationstrate
public SessionAuthenticationStrategy sessionAuthenticationStrategy() {
    List<SessionAuthenticationStrategy> stratList = new ArrayList<>();
    SessionFixationProtectionStrategy concStrat = new SessionFixationProtectionStrategy();
    stratList.add(concStrat);
    RegisterSessionAuthenticationStrategy regStrat = new RegisterSessionAuthenticationStrategy(sessionRegistry());
    stratList.add(regStrat);
    CompositeSessionAuthenticationStrategy compStrat = new CompositeSessionAuthenticationStrategy(stratList);
    return compStrat;
}

참고URL : https://stackoverflow.com/questions/11271449/how-can-i-have-list-of-all-users-logged-in-via-spring-security-my-web-applicat

반응형