Quarkus中IP认证时Sqlite查询触发BlockingOperationNotAllowedException问题
解决Quarkus中Sqlite阻塞查询导致的BlockingOperationNotAllowedException问题
完全可以通过Sqlite查询用户-IP映射信息来实现IP认证,核心是处理阻塞操作与Quarkus响应式线程池的冲突,以下是具体解决方案:
1. 用@Blocking标记认证方法
Quarkus的HttpAuthenticationMechanism默认在响应式线程池中执行,而Sqlite的JDBC操作属于阻塞IO,直接调用会触发BlockingOperationNotAllowedException。通过添加@Blocking注解,可让Quarkus将该方法调度到专门的阻塞线程池中执行,避免异常。
示例代码:
@ApplicationScoped public class IpBasedAuthMechanism implements HttpAuthenticationMechanism { @Inject EntityManager em; @Override @Blocking // 关键注解,指定方法在阻塞线程池执行 public Uni<AuthenticationMechanismOutcome> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) { String clientIp = context.request().remoteAddress().hostAddress(); // 查询Sqlite中的用户-IP映射 User ipUser = em.createQuery("SELECT u FROM User u WHERE u.ip = :clientIp", User.class) .setParameter("clientIp", clientIp) .getSingleResult(); if (ipUser != null) { // 调用身份验证管理器完成认证流程 return identityProviderManager.validate(AuthenticationRequest.of(ipUser.getUsername(), new Credential() {})) .map(ValidationResult::getAuthenticationMechanismOutcome); } return Uni.createFrom().item(AuthenticationMechanismOutcome.NOT_AUTHENTICATED); } // 实现其他必要方法(如sendChallenge等) }
2. 按需调整阻塞线程池配置(可选)
针对轻量低负载场景,Quarkus默认的阻塞线程池配置已足够。若需自定义线程数,可在application.properties中添加:
# 核心线程数 quarkus.thread-pool.core-threads=8 # 最大线程数 quarkus.thread-pool.max-threads=16
3. 替代方案:原生JDBC操作Sqlite
如果不想依赖JPA的EntityManager,也可以直接用原生JDBC配合@Blocking实现查询,逻辑更直观:
@ApplicationScoped public class IpBasedAuthMechanism implements HttpAuthenticationMechanism { @Inject DataSource dataSource; @Override @Blocking public Uni<AuthenticationMechanismOutcome> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) { String clientIp = context.request().remoteAddress().hostAddress(); String username = null; try (Connection conn = dataSource.getConnection()) { String sql = "SELECT username FROM user_ip_map WHERE ip_address = ?"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setString(1, clientIp); ResultSet rs = stmt.executeQuery(); if (rs.next()) { username = rs.getString("username"); } } } catch (SQLException e) { // 处理数据库查询异常 e.printStackTrace(); } if (username != null) { return identityProviderManager.validate(AuthenticationRequest.of(username, new Credential() {})) .map(ValidationResult::getAuthenticationMechanismOutcome); } return Uni.createFrom().item(AuthenticationMechanismOutcome.NOT_AUTHENTICATED); } // 实现其他必要方法 }
注意事项
- 确保已引入Quarkus的Sqlite扩展:
quarkus-jdbc-sqlite,在pom.xml中添加依赖即可。 - 由于部署在安全局域网且为低负载应用,阻塞操作不会引发性能问题,完全适配场景需求。
内容的提问来源于stack exchange,提问作者Alex T
相关产品推荐
相关产品推荐

