Конфигурация Spring Security всегда перенаправляется на страницу входа в системуJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Конфигурация Spring Security всегда перенаправляется на страницу входа в систему

Сообщение Anonymous »

Недавно я обновил Java, Springboot, Sprint Security и Tomcat до версий 21, 3.5.6, 6.5.5 и 10 соответственно с версий 8, 2.7.5, 5.3.23 и 9 соответственно, и в результате я обновляю свою конфигурацию безопасности.
В моей локальной среде приложение работает без проблем после внесения изменений. Однако при запуске приложения в развертывании я могу перейти на страницу входа, но каждая конечная точка перенаправляется на несуществующую конечную точку входа http://localhost:8080/custom-context/login, и я не могу войти в систему. Моя страница входа — http://localhost:8080/Login. Я обнаружил, что проблема связана с авторизацией и аутентификацией для моих конечных точек, но не смог выяснить, в чем именно заключается проблема и как ее решить.
Я думаю, что проблема многогранна и заключается в разных областях процесса аутентификации и авторизации, как в том, как я настроил Spring Security, так и в моих пользовательских фильтрах.
Я попытался изменить свой конфигурация с несколькими предложениями из текущей документации Springboot и Spring Security, в частности, касающимися настройки класса SecurityConfig. Ниже приведен мой текущий класс SecurityConfig.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean(name="customUserDetailsService")
public AccessController userDetailsService() {return new AccessController();}

@Bean
public BCryptPasswordEncoder customPasswordEncoder() {return new BCryptPasswordEncoder();}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable).authorizeHttpRequests(auth -> auth
.requestMatchers("/access/token", "/access/login", "/access/license"
"/access/refreshToken", "/licensing/**", "/ui/saveChecksumLogs",
"/ws-message/**", "/swagger-ui/**", "/v3/**", "/ui/disabledProfileUpdatedStatus",
"/ui/profileUpdatedStatus", "/ui/test").permitAll()
.anyRequest().authenticated()
).sessionManagement(httpSecuritySessionManagementConfigurer ->
httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

http.with(new CustomAuthenticationManager(), customAuthenticationManager -> {});
http.addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterAfter(new DomainAuthorizationFilter(), BasicAuthenticationFilter.class);
http.addFilterAfter(new RoleAuthorizationFilter(), BasicAuthenticationFilter.class);

return http.build();
}

@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
config.setAllowedOriginPatterns(List.of("http://*:8080", "http://*:3000", "https://*:443", "https://*:8443"));
config.setAllowCredentials(true);
config.setAllowedHeaders(List.of("*"));
config.setExposedHeaders(List.of("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}

class CustomAuthenticationManager extends AbstractHttpConfigurer {
@Autowired
UserDetailsService service;

@Override
public void configure(HttpSecurity http) throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(service);
provider.setPasswordEncoder(customPasswordEncoder());
CustomAuthenticationFilter auth = new CustomAuthenticationFilter(new ProviderManager(provider));
auth.setFilterProcessesUrl("/access/login");
http.addFilter(auth);
}
}

public CustomAuthenticationFilter customAuthenticationFilter() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider(userDetailsService());
provider.setPasswordEncoder(customPasswordEncoder());
CustomAuthenticationFilter auth = new CustomAuthenticationFilter(new ProviderManager(provider));
auth.setfilterProcessesUrl("/access/login");
return auth;
}
}

Далее идет мой класс CustomAuthenticationFilter.
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
private LicenseHelper licenseHelper;
private DomainHelper domainHelper;
private UIController uiController;
public CustomAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {

if (licenseHelper == null) { // This class type can't use injection, so do a lazy set
ServletContext servletContext = request.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
assert webApplicationContext != null;
licenseHelper = webApplicationContext.getBean(LicenseHelper.class);
}

if (domainHelper == null) { // This class type can't use injection, so do a lazy set
ServletContext servletContext = request.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils
.getWebApplicationContext(servletContext);
assert webApplicationContext != null;
domainHelper = webApplicationContext.getBean(DomainHelper.class);
}

String username = request.getParameter("username");
String password = request.getParameter("password");
String decodedUser;
String decodedPass;
try {
decodedUser = URLDecoder.decode(username, StandardCharsets.UTF_8.name());
decodedPass = URLDecoder.decode(password, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException ex) {
throw new BadCredentialsException(ex.getMessage(), ex);
}

UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(decodedUser,
decodedPass);
return authenticationManager.authenticate(authenticationToken);

}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
User user = (User) authResult.getPrincipal();
// TODO Save token string elsewhere
TokenHelper tokenHelper = new TokenHelper(user, request);
String access_token = tokenHelper.createAccessToken();
String refresh_token = tokenHelper.createRefreshToken();

// User has logged in, check if they're enabled before granting access
boolean isEnabled = false;
for (GrantedAuthority auth : user.getAuthorities()) {
String authority = auth.getAuthority();
String userEnabled = authority.substring(USER_ENABLED_SUBSTRING.length());
if (userEnabled.equals("true") || userEnabled.equals("TRUE")) {
isEnabled = true;
break;
}
}

// If admin then allow the login
if (!licenseHelper.validLicenseInstalled() && !domainHelper.isRegisteredAdmin(user.getUsername())) {
response.setStatus(FORBIDDEN.value());
response.setContentType(APPLICATION_JSON_VALUE);
response.setHeader("Access-Control-Allow-Origin", "*");
OperationStatusModel result = new OperationStatusModel("Login");
result.setResult(RequestOperationResult.ERROR.name());
result.setErrorDescription("A valid license is not installed");
new ObjectMapper().writeValue(response.getOutputStream(), result);
logger.error("A valid license is not installed, prevent login");
return;
}

if (!isEnabled) {
response.setStatus(FORBIDDEN.value());
response.setContentType(APPLICATION_JSON_VALUE);
response.setHeader("Access-Control-Allow-Origin", "*");
OperationStatusModel result = new OperationStatusModel("Login");
result.setResult(RequestOperationResult.ERROR.name());
result.setErrorDescription("Could not login, user is not enabled");
new ObjectMapper().writeValue(response.getOutputStream(), result);
logger.error("User is not enabled, cannot login");
return;
}

logger.info("Login Success!");
Map tokens = new HashMap();
response.setHeader("Access-Control-Allow-Origin", "*");

tokens.put("access_token", access_token);
tokens.put("refresh_token", refresh_token);
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), tokens);

}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {

response.setStatus(FORBIDDEN.value());
response.setContentType(APPLICATION_JSON_VALUE);
response.setHeader("Access-Control-Allow-Origin", "*");
OperationStatusModel result = new OperationStatusModel("Login");
result.setResult(RequestOperationResult.ERROR.name());
result.setErrorDescription("Could not login, incorrect username or password");
new ObjectMapper().writeValue(response.getOutputStream(), result);
logger.error("Unsuccessful Login attempt");
}
}

Далее идет мой класс CustomAuthorizationFilter.
public class CustomAuthorizationFilter extends OncePerRequestFilter {

@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getServletPath().equals("/access/login") ||
request.getServletPath().equals("/access/refreshToken") ||
request.getServletPath().equals("/access/license") ||
request.getServletPath().equals("/ui/test")) {
filterChain.doFilter(request, response);
} else {
String authorizationHeader = request.getHeader(AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256(TokenHelper.secret);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);
String username = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);

Collection authorities = new ArrayList();
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role));
});
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
username, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
} catch (Exception e) {
logger.error("ERROR Authenticating : " + e.getMessage());

response.setStatus(FORBIDDEN.value());
response.setContentType(APPLICATION_JSON_VALUE);

OperationStatusModel error = new OperationStatusModel(request.getMethod());
error.setResult(RequestOperationResult.ERROR.name());
error.setErrorDescription(e.getMessage());
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}

И наконец, мой класс AccessController, демонстрирующий реализацию UserDetailsService. Класс TokenHelper генерирует JWT с необходимыми полномочиями.
@Tag(name = "access", description = "Endpoints for logging in and verifying access of the user")
@RestController("customUserDetailsService")
@RequestMapping("/access")
@CrossOrigin(origins = "*", allowedHeaders = "*") // added to let react reach the service correctly
public class AccessController implements UserDetailsService {
private static final Logger log = LogManager.getLogger(AccessController.class);

@Autowired
UserRepository user_repo;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
OperationStatusModel result = new OperationStatusModel("RequestLogin");
CustomUser user = user_repo.findByUsername(username);
if (user == null) {
log.error("User not found: " + username);
result.setErrorDescription("The Name fields cannot be null or empty.");
result.setResult(RequestOperationResult.ERROR.name());
throw new UsernameNotFoundException("User not found in the database");
} else {
log.info("User found in database: " + username + " and domainId: " + user.getDomain().getDomainId());

}
TokenHelper tokenHelper = new TokenHelper(user, null);

Collection authorities = tokenHelper.generateAuthorities();

return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
authorities);
}
}

Одна из таких попыток исправить проблему заключалась в использовании приведенного ниже кода в SecurityConfig и замене реализации CustomAuthenticationManager подходом, более стилизованным под Spring Security. Опять же, это не сработало, и я все равно получил перенаправления.
@Bean
public AuthenticationManager authManager(UserDetailsService userService, PasswordEncoder passEncoder) {
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider(userDetailsService);
daoProvider.setPasswordEncoder(passEncoder);
return new ProviderManager(daoProvider);
}

Затем я попытался добавить этот AuthenticationManager в качестве параметра для моего CustomAuthenticationFilter, но это не сработало.
http.addFilterBefore(new CustomAuthenticationFilter(authManager(userDetailsService(), customPasswordEncoder())), UsernamePasswordAuthenticationFilter.class);

Я также пытался указать URL-адрес страницы входа, но это не сработало. Это было между отключением CSRF и определениями сопоставителей запросов. Я могу без проблем открыть страницу в своем браузере, но любая попытка входа приведет к перенаправлению.
.formLogin(form -> form.loginPage("/Login").permitAll())

Наконец, я попытался просмотреть журналы своего проекта и журналы сервера Tomcat, но не смог найти ничего, что указывало бы на то, в чем может быть проблема. При необходимости я могу опубликовать их.
Прошу прощения, если что-то покажется вам непонятным. Я исправлю все ошибки, чтобы внести больше ясности.
Журнал Catalina
09-Oct-2025 11:42:40.573 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version name: Apache Tomcat/10.1.46
09-Oct-2025 11:42:40.589 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Sep 8 2025 14:26:21 UTC
09-Oct-2025 11:42:40.591 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version number: 10.1.46.0
09-Oct-2025 11:42:40.597 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Windows 11
09-Oct-2025 11:42:40.597 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 10.0
09-Oct-2025 11:42:40.599 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
09-Oct-2025 11:42:40.599 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: C:\Program Files\Java\jdk-21
09-Oct-2025 11:42:40.599 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Version: 21.0.8+12-LTS-250
09-Oct-2025 11:42:40.599 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log JVM Vendor: Oracle Corporation
09-Oct-2025 11:42:40.606 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_BASE: C:\Program Files\Apache Software Foundation\Tomcat 10.1
09-Oct-2025 11:42:40.606 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log CATALINA_HOME: C:\Program Files\Apache Software Foundation\Tomcat 10.1
09-Oct-2025 11:42:40.647 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 10.1\conf\logging.properties
09-Oct-2025 11:42:40.649 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
09-Oct-2025 11:42:40.649 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djdk.tls.ephemeralDHKeySize=2048
09-Oct-2025 11:42:40.649 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.protocol.handler.pkgs=org.apache.catalina.webresources
09-Oct-2025 11:42:40.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dsun.io.useCanonCaches=false
09-Oct-2025 11:42:40.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang=ALL-UNNAMED
09-Oct-2025 11:42:40.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
09-Oct-2025 11:42:40.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.io=ALL-UNNAMED
09-Oct-2025 11:42:40.650 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util=ALL-UNNAMED
09-Oct-2025 11:42:40.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
09-Oct-2025 11:42:40.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
09-Oct-2025 11:42:40.652 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 10.1
09-Oct-2025 11:42:40.654 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 10.1
09-Oct-2025 11:42:40.657 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 10.1\temp
09-Oct-2025 11:42:40.672 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [C:\Program Files\Java\jdk-21\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\Program Files\Common Files\Oracle\Java\javapath;C:\Program Files (x86)\Common Files\Oracle\Java\java8path;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Users\Patrick\AppData\Local\Programs\Python\Python37-32\Scripts\;C:\Users\Patrick\AppData\Local\Programs\Python\Python37-32\;C:\Users\Patrick\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Java\jre-1.8\bin;;.]
09-Oct-2025 11:42:41.936 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
09-Oct-2025 11:42:42.077 INFO [main] org.apache.catalina.startup.Catalina.load Server initialization in [2050] milliseconds
09-Oct-2025 11:42:42.316 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service [Catalina]
09-Oct-2025 11:42:42.318 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/10.1.46]
09-Oct-2025 11:42:42.393 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\custom-context.war]
09-Oct-2025 11:43:05.081 INFO [main] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
09-Oct-2025 11:44:09.744 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\custom-context.war] has finished in [87,349] ms
09-Oct-2025 11:44:09.784 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\host-manager]
09-Oct-2025 11:44:10.242 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\host-manager] has finished in [490] ms
09-Oct-2025 11:44:10.244 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\manager]
09-Oct-2025 11:44:10.528 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\manager] has finished in [282] ms
09-Oct-2025 11:44:10.528 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\ROOT]
09-Oct-2025 11:44:10.628 INFO [main] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\ROOT] has finished in [100] ms
09-Oct-2025 11:44:10.643 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
09-Oct-2025 11:44:10.701 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in [88608] milliseconds
09-Oct-2025 11:45:42.930 INFO [Thread-2] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["http-nio-8080"]
09-Oct-2025 11:45:42.960 INFO [Thread-2] org.apache.catalina.core.StandardService.stopInternal Stopping service [Catalina]
09-Oct-2025 11:45:43.298 WARNING [Thread-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [custom-context] appears to have started a thread named [Log4j2-TF-4-Scheduled-2] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.base/jdk.internal.misc.Unsafe.park(Native Method)
java.base/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:269)
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1763)
java.base/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182)
java.base/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899)
java.base/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1070)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
java.base/java.lang.Thread.run(Thread.java:1583)
09-Oct-2025 11:45:43.300 WARNING [Thread-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [custom-context] appears to have started a thread named [mysql-cj-abandoned-connection-cleanup] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.base/jdk.internal.misc.Unsafe.park(Native Method)
java.base/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:269)
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1852)
java.base/java.lang.ref.ReferenceQueue.await(ReferenceQueue.java:71)
java.base/java.lang.ref.ReferenceQueue.remove0(ReferenceQueue.java:143)
java.base/java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:218)
com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:84)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
java.base/java.lang.Thread.run(Thread.java:1583)
09-Oct-2025 11:45:43.331 INFO [Thread-2] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"]
09-Oct-2025 11:45:43.378 INFO [Thread-2] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]


Подробнее здесь: https://stackoverflow.com/questions/797 ... login-page
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»