Я боролся с этим слишком много дней и мне действительно нужна помощь. Я пытаюсь использовать Spring-Boot 3.3.0 для создания необычного поставщика аутентификации. Мне нужно, чтобы это работало так:
public class RefererAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("**","GET");
public RefererAuthenticationFilter(AuthenticationManager authenticationManager) {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String url = request.getHeader( "Referer" );
String fetchDest = request.getHeader( "Sec-Fetch-Dest" );
String id = request.getParameter( "id" );
String name = request.getParameter( "name" );
String email = request.getParameter( "email" );
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
Referer referer = new Referer();
referer.setUrl(url);
referer.setFetchDest(fetchDest);
referer.setId(id);
referer.setName(name);
referer.setEmail(email);
referer.setIpAddress(ipAddress);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( referer, null );
return this.getAuthenticationManager().authenticate(authRequest);
}
}
@Component
public class RefererAuthenticationProvider implements AuthenticationProvider {
@Value("${referer}")
private String validReferer;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken challengeAuth = (UsernamePasswordAuthenticationToken) authentication;
log.debug( "starting authentication ..." );
Referer referer = (Referer) challengeAuth.getPrincipal();
if ( referer.getUrl().startsWith(validReferer) &&
referer.getFetchDest().equals("iframe") ) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<SimpleGrantedAuthority>();
grantedAuthorities.add(authority);
return new UsernamePasswordAuthenticationToken( referer, null, grantedAuthorities);
}
throw new BadCredentialsException("referer did not match within the iframe");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals( UsernamePasswordAuthenticationToken.class );
}
}
@Configuration
@AllArgsConstructor
@EnableWebSecurity(debug = true)
public class SecurityConfig {
@Autowired
RefererAuthenticationProvider refererAuthenticationProvider;
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(refererAuthenticationProvider);
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
RefererAuthenticationFilter refererAuthenticationFilter = new RefererAuthenticationFilter(authenticationManager);
refererAuthenticationFilter.setAuthenticationManager(authenticationManager);
return http
.csrf(AbstractHttpConfigurer::disable)
.addFilterAt(refererAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests( request -> { request
.anyRequest().authenticated();
})
.headers( headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable) )
.build();
}
}
В конце концов, это просто говорит мне...
java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AuthenticationManager.authenticate(org.springframework.security.core.Authentication)"
because the return value of "com.example.security.filter.RefererAuthenticationFilter.getAuthenticationManager()" is null
Я думал, что смогу использовать AuthenticationManager по умолчанию.
Чтобы еще больше усложнить ситуацию, мне нужно несколько AuthenticationProviders. Я хочу, чтобы сначала попробовали эту версию, а затем okta-spring-boot-starter 3.0.6. Я не уверен, могут ли они сосуществовать в одном AuthenticationManager, кто его предоставляет, и где именно я бы попытался разместить свой RefererAuthenticationFilter в цепочке фильтров с Okta, которая выглядит так
org.springframework.security.web.session.DisableEncodeUrlFilter@4bf806ab,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@2e7b49c0,
org.springframework.security.web.context.SecurityContextHolderFilter@1e26110d,
org.springframework.security.web.header.HeaderWriterFilter@1e1b3778,
org.springframework.web.filter.CorsFilter@5dd7342f,
org.springframework.security.web.authentication.logout.LogoutFilter@1865d91,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@5d116afe,
org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@1780aa5d,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@264c6be6,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@3f60f8c4,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@4650f833,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@3acc81dd,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@34a66cdd,
org.springframework.security.web.access.ExceptionTranslationFilter@206f53b0,
org.springframework.security.web.access.intercept.AuthorizationFilter@fbb75c2
NullPointerException
, с которым вы столкнулись, связано с тем, что AuthenticationManager
неправильно инициализирован в вашем RefererAuthenticationFilter
. Чтобы решить эту проблему, вам необходимо явно установить AuthenticationManager
в своем пользовательском фильтре. Кроме того, для поддержки нескольких AuthenticationProviders
вы можете настроить Spring Security на использование списка провайдеров.
Вот обновленная версия вашей конфигурации:
public class RefererAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("**","GET");
public RefererAuthenticationFilter(AuthenticationManager authenticationManager) {
super(DEFAULT_ANT_PATH_REQUEST_MATCHER);
setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
String url = request.getHeader("Referer");
String fetchDest = request.getHeader("Sec-Fetch-Dest");
String id = request.getParameter("id");
String name = request.getParameter("name");
String email = request.getParameter("email");
String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
ipAddress = request.getRemoteAddr();
}
Referer referer = new Referer();
referer.setUrl(url);
referer.setFetchDest(fetchDest);
referer.setId(id);
referer.setName(name);
referer.setEmail(email);
referer.setIpAddress(ipAddress);
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(referer, null);
return this.getAuthenticationManager().authenticate(authRequest);
}
}
Настройте несколько AuthenticationProviders
и интегрируйте их с AuthenticationManager
в свой SecurityConfig
:
@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig {
@Autowired
private RefererAuthenticationProvider refererAuthenticationProvider;
@Autowired
private OktaOAuth2AuthenticationProvider oktaAuthenticationProvider; // Assuming you have a custom Okta provider
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.authenticationProvider(refererAuthenticationProvider);
authenticationManagerBuilder.authenticationProvider(oktaAuthenticationProvider);
AuthenticationManager authenticationManager = authenticationManagerBuilder.build();
RefererAuthenticationFilter refererAuthenticationFilter = new RefererAuthenticationFilter(authenticationManager);
return http
.csrf(AbstractHttpConfigurer::disable)
.addFilterAt(refererAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests(request -> request.anyRequest().authenticated())
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.build();
}
@Bean
public RefererAuthenticationProvider refererAuthenticationProvider() {
return new RefererAuthenticationProvider();
}
@Bean
public OktaOAuth2AuthenticationProvider oktaAuthenticationProvider() {
return new OktaOAuth2AuthenticationProvider(); // Customize as needed
}
}
убедиться, что реализации провайдеровRefererAuthenticationProvider
и Okta определены правильно:
@Component
public class RefererAuthenticationProvider implements AuthenticationProvider {
@Value("${referer}")
private String validReferer;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken challengeAuth = (UsernamePasswordAuthenticationToken) authentication;
log.debug("starting authentication ...");
Referer referer = (Referer) challengeAuth.getPrincipal();
if (referer.getUrl().startsWith(validReferer) && referer.getFetchDest().equals("iframe")) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(authority);
return new UsernamePasswordAuthenticationToken(referer, null, grantedAuthorities);
}
throw new BadCredentialsException("referer did not match within the iframe");
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Обратите внимание, что Генеративный ИИ (например, ChatGPT) запрещен , и прочтите Справочный центр: Политика ИИ. Запрещено использовать инструменты искусственного интеллекта для создания или изменения содержания контента, который вы публикуете в Stack Overflow.