Vaadin 23 не может полностью перезагрузить приложение после повторного развертывания
Прямо сейчас я готовлю свое приложение Vaadin 23.2.5 к производству, и очень часто после повторного развертывания приложение не может полностью перезагрузиться и зависает с толстой синей полосой выполнения вверху.
Единственная проблема, которую я вижу, это следующая проблема JS в консоли браузера:
Fire Fox
Хром
Кроме того, исходя из моих предыдущих вопросов на эту тему — я полностью удалил компонент Grid из приложения, но, как вы видите, проблема все еще существует. Как решить эту проблему?
ОБНОВЛЕНО
Мои конфиги:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {
private final ClientRegistrationRepository clientRegistrationRepository;
private final GrantedAuthoritiesMapper authoritiesMapper;
private final ProfileService profileService;
SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository,
GrantedAuthoritiesMapper authoritiesMapper, ProfileService profileService) {
this.clientRegistrationRepository = clientRegistrationRepository;
this.authoritiesMapper = authoritiesMapper;
this.profileService = profileService;
SecurityContextHolder.setStrategyName(VaadinAwareSecurityContextHolderStrategy.class.getName());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
// Enable OAuth2 login
.oauth2Login(oauth2Login ->
oauth2Login
.clientRegistrationRepository(clientRegistrationRepository)
.userInfoEndpoint(userInfoEndpoint ->
userInfoEndpoint
// Use a custom authorities mapper to get the roles from the identity provider into the Authentication token
.userAuthoritiesMapper(authoritiesMapper)
)
// Use a Vaadin aware authentication success handler
.successHandler(new KeycloakVaadinAuthenticationSuccessHandler(profileService))
)
// Configure logout
.logout(logout ->
logout
// Enable OIDC logout (requires that we use the 'openid' scope when authenticating)
.logoutSuccessHandler(logoutSuccessHandler())
// When CSRF is enabled, the logout URL normally requires a POST request with the CSRF
// token attached. This makes it difficult to perform a logout from within a Vaadin
// application (since Vaadin uses its own CSRF tokens). By changing the logout endpoint
// to accept GET requests, we can redirect to the logout URL from within Vaadin.
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
);
}
@Bean
@Primary
public SpringViewAccessChecker springViewAccessChecker(AccessAnnotationChecker accessAnnotationChecker) {
return new KeycloakSpringViewAccessChecker(accessAnnotationChecker, "/oauth2/authorization/keycloak");
}
private OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler() {
var logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// Don't apply security rules on our static pages
web.ignoring().antMatchers("/session-expired", "/images/*");
}
@Bean
public PolicyFactory htmlSanitizer() {
// This is the policy we will be using to sanitize HTML input
return Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
}
}
@Component
class VaadinSessionConfiguration implements VaadinServiceInitListener, SystemMessagesProvider, SessionDestroyListener {
private final String relativeSessionExpiredUrl;
VaadinSessionConfiguration(ServerProperties serverProperties) {
relativeSessionExpiredUrl = UriComponentsBuilder.fromPath(serverProperties.getServlet().getContextPath()).path("logout").build().toUriString();
}
@Override
public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
var messages = new CustomizedSystemMessages();
// Redirect to a specific screen when the session expires. In this particular case we don't want to logout
// just yet. If you would like the user to be completely logged out when the session expires, this URL
// should the logout URL.
messages.setSessionExpiredURL(relativeSessionExpiredUrl);
return messages;
}
@Override
public void sessionDestroy(SessionDestroyEvent event) {
// We also want to destroy the underlying HTTP session since it is the one that contains the authentication
// token.
try {
event.getSession().getSession().invalidate();
} catch (Exception ignore) {
// Session was probably already invalidated.
}
}
@Override
public void serviceInit(ServiceInitEvent event) {
event.getSource().setSystemMessagesProvider(this);
event.getSource().addSessionDestroyListener(this);
}
}
public final class VaadinAwareSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
@Override
public void clearContext() {
contextHolder.remove();
}
@Override
@NonNull
public SecurityContext getContext() {
var context = contextHolder.get();
if (context == null) {
context = getFromVaadinSession().orElseGet(() -> {
var newCtx = createEmptyContext();
// This copies the behaviour of ThreadLocalSecurityContextHolder.
contextHolder.set(newCtx);
return newCtx;
});
}
return context;
}
@NonNull
private Optional<SecurityContext> getFromVaadinSession() {
// Don't store this security context in the ThreadLocal as that may lead to the context leaking
// into other sessions as threads may be reused.
var session = VaadinSession.getCurrent();
if (session == null) {
return Optional.empty();
}
var securityContext = session.getSession().getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
if (securityContext instanceof SecurityContext) {
return Optional.of((SecurityContext) securityContext);
} else {
return Optional.empty();
}
}
@Override
public void setContext(@NonNull SecurityContext securityContext) {
contextHolder.set(requireNonNull(securityContext));
}
@Override
@NonNull
public SecurityContext createEmptyContext() {
return new SecurityContextImpl();
}
}
ОБНОВЛЕНО 1