복붙노트

[SPRING] 기본 시스템 인증 / 사용자가있는 SecurityContext

SPRING

기본 시스템 인증 / 사용자가있는 SecurityContext

스프링 애플리케이션에서 SecurityContext는 항상 인증을 보유하고 싶습니다. 일반 UsernamePasswordAuthenticationToken이 아닌 경우 "시스템 사용자"를 설명하는 PreAuthenticatedAuthenticationToken이됩니다. 이것은 사용자를 필요로하는 다른 시스템 기능 내에서 이유가 있습니다. 사용자 컨텍스트가 없으면 특별한 처리를 피하기 위해 시스템 컨텍스트를 추가하기 만하면됩니다. IMHO, 이것은 단일 책임 원칙과 관련이 있습니다.

이를 달성하기 위해 간단히 자체 SecurityContextHolderStrategy를 구현하고이를 SecurityContextHolder.setStrategyName (MyStrategyClassName)을 사용하여 SecurityContextHolder로 설정할 수 있습니다.

이제 문제 :

기본 SecurityContextHolderStrategy는 ThreadLocalSecurityContextHolderStrategy입니다. 나는이 전략과 그것이 어떻게 작동하는지에 만족합니다. 내가 바꿀 유일한 것은 getContext () 메소드입니다.

public SecurityContext getContext() {
    SecurityContext ctx = CONTEXT_HOLDER.get();

    if (ctx == null) {
        ctx = createEmptyContext();
        CONTEXT_HOLDER.set(ctx);
    }
    return ctx;
}

public SecurityContext getContext() {
    SecurityContext ctx = CONTEXT_HOLDER.get();

    if (ctx == null) {
        ctx = createEmptyContext();
        Authentication authentication = new PreAuthenticatedAuthenticationToken("system", null);
        authentication.setAuthenticated(true);
        ctx.setAuthentication(authentication);
        CONTEXT_HOLDER.set(ctx);
    }
    return ctx;
}

ThreadLocalSecurityContextHolderStrategy 클래스가 public이 아니기 때문에 불가능합니다. 물론 ThreadLocalSecurityContextHolderStrategy 코드를 내 자신의 SecurityContextHolderStrategy에 붙여 넣기 만하면되고 원하는 방식으로 getContext () 메서드를 구현할 수 있습니다. 그러나 이것은 내가 잘못된 길 위에있을 수 있다는 느낌을줍니다.

새 SecurityContext의 기본값으로 "시스템 사용자"인증을 얻으려면 어떻게해야합니까?

최신 정보

위의 내 접근 방식은 분명히 극단적 인 침입으로 중복 코드를 생성하고 웹 필터 체인 내에서 특별한 처리가 필요하므로 해결 방법이 아닙니다. 하지만 내 목표를 이해해야합니다. 나는 원시 스프링 보안 구현에 가능한 한 매끄럽게 맞는 솔루션을 찾고있다. 제 문제는 제가 침략적 접근법에 상당히 고정되어 있다는 것입니다. 이 문제를 어떻게 해결할 수 있습니까? 내가이 요구 조건을 가진 첫 번째 사람이라고 나는 상상할 수 없다. 아니면 전체 개념이 완전히 틀렸는가?

해결법

  1. ==============================

    1.만약에 다음과 같은 해결책을 얻었 으면 아주 매끄럽고 충돌이나 간섭을하지 않아야합니다. generall에는 널 인증을받을 두 가지 상황이 있습니다.

    만약에 다음과 같은 해결책을 얻었 으면 아주 매끄럽고 충돌이나 간섭을하지 않아야합니다. generall에는 널 인증을받을 두 가지 상황이 있습니다.

    솔리 톤 1.

    여전히 메인 시스템 스레드에 문제가 있습니다. 이것은 시스템 시작시 컨텍스트를 설정하기 만하면 쉽게 처리 할 수 ​​있습니다. 또한 모든 자식 스레드가 SecurityContext를 상속 할 수 있도록 InheritableThreadLocalSecurityContextHolderStrategy를 사용하도록 SecurityContextHolder를 구성합니다. 응용 프로그램 컨텍스트가 새로 고침 될 때마다이 설정이 적용됩니다. 보안 컨텍스트와 관련된 테스트를 실행할 때 @DirtiesContext를 사용할 수 있습니다.

    @Component
    public class SecurityContextConfiguration {
    
        @EventListener
        public void setupSecurityContext(ContextRefreshedEvent event) {
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
        SecurityContextHolder.getContext().setAuthentication(new SystemAuthentication());
        }
    }
    

    Solyon 제 2.

    MODE_INHERITABLETHREADLOCAL을 사용하여 SecurityContextHolder를 구성했습니다. 예약 된 스레드는 그의 부모 Securitycontext를 inheriet합니다. 내 유스 케이스에서는 다음과 같은 의미가 있으므로 필요하지 않습니다. 예약 된 작업이 사용자 작업으로 초기화되면 사용자 작업 SecurityContext에서 실행됩니다. 시스템 재부팅시 예정된 작업을 풀고 싶지는 않아도 그대로 유지할 것입니다. 그러면 사용자 SecurityContext로 초기화되기 전과 동일한 작업이 재부팅시 시스템 SecurityContext와 함께 초기화되지 않습니다. 이것은 inconsitence를 생성합니다. 그래서 나는 나의 스케줄러를 구성한다.

    간단히 @Scheduled 주석을 DelegatingSecurityContextScheduledExecutorService에 의해 실행되도록 구성하여 SecurityContext를 설정할 수 있도록합니다.

    @EnableScheduling
    @Configuration
    public class SystemAwareSchedulerConfiguration implements SchedulingConfigurer {
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
        }
    
        @Bean
        public ScheduledExecutorService taskExecutor() {
        ScheduledExecutorService delegateExecutor = Executors.newSingleThreadScheduledExecutor();
        SecurityContext schedulerContext = createSchedulerSecurityContext();
        return new DelegatingSecurityContextScheduledExecutorService(delegateExecutor, schedulerContext);
        }
    
        private SecurityContext createSchedulerSecurityContext() {
        SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
        securityContext.setAuthentication(new SystemAuthentication());
        return securityContext;
        }
    
    }
    

    이 두 가지 구성을 사용하면 스레드가 웹 컨테이너에 의해 초기화되지 않은 경우 항상 SystemUser 컨텍스트를 갖게됩니다.

  2. ==============================

    2.createEmptyContext () 내에서 채워진 컨텍스트를 만드는 것이 적합하지 않습니다. o)

    createEmptyContext () 내에서 채워진 컨텍스트를 만드는 것이 적합하지 않습니다. o)

    "요청이 인증되면 일반적으로 인증은 사용중인 인증 메커니즘에 의해 SecurityContextHolder가 관리하는 스레드 로컬 SecurityContext에 저장됩니다.", UsernamePasswordAuthenticationFilter를 확장하고 attemptAuthentication을 덮어 씁니다. 사용자 이름 암호 확인에 실패한 경우 PreAuthenticatedAuthenticationToken을 설정합니다.

    편집하다

    시스템 내부 작업은 실행 방법에 따라 어떻게 달라지는 지 생각합니다. Executor의 경우 위에서 설명한 것처럼 이러한 실행을 실행하는 스레드에서 컨텍스트를 설정하는 예제가 있습니다.

    @Bean
    public Executor taskExecutor() {
        ScheduledExecutorService delegateExecutor = Executors.newSingleThreadScheduledExecutor();
        SecurityContext schedulerContext = createSchedulerSecurityContext();
        return new DelegatingSecurityContextScheduledExecutorService(delegateExecutor, schedulerContext);
    }
    
    private SecurityContext createSchedulerSecurityContext() {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
    
        Authentication authentication = new PreAuthenticatedAuthenticationToken("system", null);
        authentication.setAuthenticated(true);
        context.setAuthentication(authentication);
    
        return context;
    }
    

    이 Bean을 생성하는 @Configuration은 SchedulingConfigurer를 구현합니다.

  3. from https://stackoverflow.com/questions/47078381/securitycontext-with-default-system-authentication-user by cc-by-sa and MIT license