簡體   English   中英

切換帶有特定請求標頭的請求的Spring Security

[英]Toggle Spring Security for the requests with particular Request Header

我試圖切換/旁路/禁用春季安全 (身份驗證和授權) 具有特殊請求頭中的所有請求

例如,如果使用該請求標頭命中一個請求URL,則應該繞過Spring Security,否則就不應該繞過Spring Security。

為此,我正在使用以下requestMatchers Spring Security配置:

@Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring()
        .antMatchers(HttpMethod.GET)
        .antMatchers(HttpMethod.OPTIONS)
        .requestMatchers(new RequestHeaderRequestMatcher("TEST-HEADER","TEST-VALUE"));
  }

我剩下的安全配置是:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity (prePostEnabled = true)
@ConditionalOnProperty (name = "security.enabled", havingValue = "true", matchIfMissing = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private SecurityProps securityProps;

  @Autowired
  private MyUserDetailsService myUserDetailsService;

  @Autowired
  private MyAuthenticationEntryPoint myAuthenticationEntryPoint;

  @Autowired
  private MyCORSFilter myCORSFilter;

  public SecurityConfig() {
    SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
  }


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

    http.sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .csrf().disable()
        .addFilterBefore(myCORSFilter, SessionManagementFilter.class)
        .addFilterBefore(requestHeaderFilter(), RequestHeaderAuthenticationFilter.class)
        .authenticationProvider(preauthAuthProvider())
        .authorizeRequests()
          .antMatchers(HttpMethod.GET, securityProps.getNoAuthGetPattern()).permitAll()
          .antMatchers(HttpMethod.OPTIONS, securityProps.getNoAuthOptionsPattern()).permitAll()
          .requestMatchers(new RequestHeaderRequestMatcher("TEST-HEADER","TEST-VALUE")).permitAll()
          .anyRequest().authenticated()
        .and()
        .exceptionHandling()
        .authenticationEntryPoint(myAuthenticationEntryPoint);
  }

  @Autowired
  @Override
  protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(preauthAuthProvider());
  }

  @Override
  public void configure(WebSecurity web) throws Exception {
    web.ignoring()
        .antMatchers(HttpMethod.GET)
        .antMatchers(HttpMethod.OPTIONS)
        .requestMatchers(new RequestHeaderRequestMatcher("TEST-HEADER","TEST-VALUE"));
  }

  public RequestHeaderAuthenticationFilter requestHeaderFilter() throws Exception {
    RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
    requestHeaderAuthenticationFilter.setPrincipalRequestHeader(MySecurityConstants.LOGIN_HEADER);
    requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager());
    requestHeaderAuthenticationFilter.setExceptionIfHeaderMissing(false);
    requestHeaderAuthenticationFilter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
      @Override
      public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
          AuthenticationException exception) throws IOException, ServletException {
        if (exception instanceof MySecurityException) {
          myAuthenticationEntryPoint.commenceMySecurityException(request, response, (MySecurityException) exception);
        } else if (exception instanceof UsernameNotFoundException) {
          myAuthenticationEntryPoint.commenceUsernameNotFoundException(request, response,
              (UsernameNotFoundException) exception);
        } else if (exception instanceof PreAuthenticatedCredentialsNotFoundException) {
          myAuthenticationEntryPoint.commence(request, response, exception);
        }
      }
    });
    return requestHeaderAuthenticationFilter;
  }

  @Bean
  public PreAuthenticatedAuthenticationProvider preauthAuthProvider() throws Exception {
    PreAuthenticatedAuthenticationProvider authProvider = new PreAuthenticatedAuthenticationProvider();
    authProvider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
    return authProvider;
  }

  @Bean
  public UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> userDetailsServiceWrapper()
      throws Exception {
    UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper =
        new UserDetailsByNameServiceWrapper<>();
    wrapper.setUserDetailsService(ivyUserDetailsService);
    return wrapper;
  }

}

通過以上設置,我無法禁用/繞過Spring Security,並且遇到AuthenticationCredentialsNotFoundException異常:

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

誰能幫助我確定我做錯了什么? 我的方法正確嗎,或者我需要做其他事情才能做到這一點?

編輯:我在beforeInvocation()方法的org.springframework.security.access.intercept.AbstractSecurityInterceptor類中獲取此異常,嘗試從SecurityContextHolder獲取身份驗證對象。 AbstractSecurityInterceptor由其子類MethodSecurityInterceptor調用,該子類是從我的Spring控制器 (由@PreAuthorize注釋)中@PreAuthorize

我認為您的旁路運行良好。 它跳過檢查。

安全性的授權檢查部分從SecurityContext獲取經過身份驗證的對象,當請求通過Spring安全性過濾器時將設置該對象。

因此,當您跳過安全過濾器時,尚未設置SecurityContext,因此錯誤

您可以執行以下操作為“自定義標題案例”手動進行設置

try {
    SecurityContext ctx = SecurityContextHolder.createEmptyContext();
    SecurityContextHolder.setContext(ctx);
    ctx.setAuthentication(event.getAuthentication());
} finally {
    SecurityContextHolder.clearContext();
}

編輯1:

回答所有查詢。

但是,如果真是這樣,那么我猜所有的GET調用也應該都失敗了,但是我的GET調用工作正常。

由於已添加此行,因此從安全檢查中跳過了所有GET調用。

.antMatchers(HttpMethod.GET, securityProps.getNoAuthGetPattern()).permitAll()

在哪里可以添加您提到的代碼? 任何特定的過濾器或其他地方?

我在過濾器中做了類似的事情。 在這里參考

查看Answer中的TokenAuthenticationFilter類。 在哪里手動設置。

注意:它的JWT實現但值得參考

UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (tokenHelper.validateToken(authToken, userDetails)) {
    // create authentication
    TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails);
    authentication.setToken(authToken);
    SecurityContextHolder.getContext().setAuthentication(authentication);
}

您的答案是什么事件?

我剛從Some Answer那里得到這種情況,現在找不到它的鏈接。 但是您可以像上面這樣設置setAuthentication

Authentication authentication = new PreAuthenticatedAuthenticationToken("system", null);
authentication.setAuthenticated(true);
context.setAuthentication(authentication);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM