在JAR文件中添加外部JAR依赖关系

发布于 2025-02-10 15:42:08 字数 14347 浏览 1 评论 0 原文

Backgorund:我正在尝试为我的旧应用程序添加USERSTORAGESPI,以便我们可以使用现有的用户凭据登录。我遵循此教程,示例应用程序的完整源代码在这里

此应用程序正在存储明文密码,并直接比较它们。但是,我的旧数据库以加密格式存储密码。为了测试示例用户,我将凭据以bcrypt格式存储,并且在我的CustomuserSerstorageProvider类中覆盖了以下方法(ISVALID(...))。

方法1:

public class CustomUserStorageProvider implements UserStorageProvider, 
      UserLookupProvider,
      CredentialInputValidator,
      UserQueryProvider {
    
      ....
    
     @Override
        public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) {
            log.info("[I57] isValid(realm={},user={},credentialInput.type={})",realm.getName(), user.getUsername(), credentialInput.getType());
            if( !this.supportsCredentialType(credentialInput.getType())) {
                return false;
            }
            StorageId sid = new StorageId(user.getId());
            String username = sid.getExternalId();
            
            try ( Connection c = DbUtil.getConnection(this.model)) {
    
                log.info("Username to query :: " + username);
                PreparedStatement st = c.prepareStatement("select password from users where username = ?");
                st.setString(1, username);
                st.execute();
                ResultSet rs = st.getResultSet();
                log.info("RS " + rs);
                if ( rs.next()) {
                    String pwd = rs.getString(1);
    
                    log.info("Password coming from query :: " + pwd);
                    log.info("Password coming from user input :: " + credentialInput.getChallengeResponse());
    

PasswordEncoder enc = new BCryptPasswordEncoder();
                    log.info(" enc.matches(pwd, credentialInput.getChallengeResponse()) " +  enc.matches(pwd, credentialInput.getChallengeResponse()));
                    return  enc.matches(pwd, credentialInput.getChallengeResponse());
                }
                else {
                    return false;
                }
            }
            catch(SQLException ex) {
                throw new RuntimeException("Database error:" + ex.getMessage(),ex);
            }
        }
    
    }

当我将罐子放入相关路径时,KeyCloak可以阅读自定义提供商。我还可以看到,KeyCloak正在显示此新数据库中的所有导入用户,但是,在代码试图比较密码时,我在KeyCloak日志中获得以下例外。

2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) RS org.postgresql.jdbc.PgResultSet@75dadacb
2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) Password coming from query :: $2a$12$rrtl/vDlCCF0cK0aKu5H6uW30B4fp9cIrTQlHPMayQTR9ToZicEoW
2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) Password coming from user input :: test
2022-06-24 15:53:30,567 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-2) Uncaught server error: java.lang.NoClassDefFoundError: org/springframework/security/crypto/password/PasswordEncoder
        at com.test.spi.provider.CustomUserStorageProvider.isValid(CustomUserStorageProvider.java:147)
        at org.keycloak.credential.UserCredentialStoreManager.lambda$validate$4(UserCredentialStoreManager.java:164)
        at java.base/java.util.Collection.removeIf(Collection.java:576)
        at org.keycloak.credential.UserCredentialStoreManager.validate(UserCredentialStoreManager.java:164)
        at org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:151)
        at org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:110)
        at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.validatePassword(AbstractUsernameFormAuthenticator.java:229)
        at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.validateUserAndPassword(AbstractUsernameFormAuthenticator.java:150)
        at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.validateForm(UsernamePasswordForm.java:55)
        at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.action(UsernamePasswordForm.java:48)
        at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:169)
        at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:990)
        at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:321)
        at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:292)
        at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:276)
        at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:349)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:71)
        at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
        at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassNotFoundException: org.springframework.security.crypto.password.PasswordEncoder
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:107)
        at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:57)
        ... 65 more

我还尝试在启动应用程序中添加passwordEncoder作为bean,并将其添加为CustomuSerstorageProvider类中的自动依赖项,但我得到了同样的例外。

方法2:

@SpringBootApplication
public class SpiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpiApplication.class, args);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

-----
@Service
public class CustomUserStorageProvider implements UserStorageProvider, 
  UserLookupProvider,
  CredentialInputValidator,
  UserQueryProvider {

    @Autowired
    PasswordEncoder enc ;

我的pom.xml依赖关系在这里:

<dependencies>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
</dependency>

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-core</artifactId>
    <version>18.0.0</version>
    
</dependency>

<!-- User Storage SPI dependency -->
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-server-spi</artifactId>
    <version>18.0.0</version>
    </dependency>

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-server-spi</artifactId>
    <version>18.0.0</version>
</dependency>
<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.2.4</version>
                </plugin>
            </plugins>
        </pluginManagement>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>

<shadedArtifactAttached>true</shadedArtifactAttached>
                    </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

我正在使用此命令来生成JAR文件并将其保存在keyCloak-bloak-bloak-bloak-18.0.0/ providers/ package中。

mvn package

请以正确的方法为我提供帮助。我也在这个论坛上介绍了几篇博客文章和问题,但没有获得适当的解决方案。 tia。

主要问题: 我什至在Eclipse中设置了此项目,并尝试将项目导出为JAR文件(可运行的jar/jar两者)。产生的远罐子的尺寸很大。 32 MB而不是由Shade插件创建的16KB,但例外保持不变。为什么这种依赖性未在JAR的类Pather中添加?我无法使用此JAR添加ClassPath的第三方应用程序,因此必须将其嵌入最终罐子中。请帮忙。我花了很多时间,我跑到了新的解决方法上进行尝试。

Backgorund : I am trying to add UserStorageSPI for my legacy application, so that we can use existing user credentials to log in. I have followed this tutorial, and the full source code for the sample application is available here.

This application is storing plaintext passwords and compares them directly. However, my legacy database stores the passwords in an encrypted format. To test a sample user, I stored the credentials in bcrypt format and I overrode the following method (isValid(...)), in my CustomUserStorageProvider class.

Approach 1:

public class CustomUserStorageProvider implements UserStorageProvider, 
      UserLookupProvider,
      CredentialInputValidator,
      UserQueryProvider {
    
      ....
    
     @Override
        public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) {
            log.info("[I57] isValid(realm={},user={},credentialInput.type={})",realm.getName(), user.getUsername(), credentialInput.getType());
            if( !this.supportsCredentialType(credentialInput.getType())) {
                return false;
            }
            StorageId sid = new StorageId(user.getId());
            String username = sid.getExternalId();
            
            try ( Connection c = DbUtil.getConnection(this.model)) {
    
                log.info("Username to query :: " + username);
                PreparedStatement st = c.prepareStatement("select password from users where username = ?");
                st.setString(1, username);
                st.execute();
                ResultSet rs = st.getResultSet();
                log.info("RS " + rs);
                if ( rs.next()) {
                    String pwd = rs.getString(1);
    
                    log.info("Password coming from query :: " + pwd);
                    log.info("Password coming from user input :: " + credentialInput.getChallengeResponse());
    

PasswordEncoder enc = new BCryptPasswordEncoder();
                    log.info(" enc.matches(pwd, credentialInput.getChallengeResponse()) " +  enc.matches(pwd, credentialInput.getChallengeResponse()));
                    return  enc.matches(pwd, credentialInput.getChallengeResponse());
                }
                else {
                    return false;
                }
            }
            catch(SQLException ex) {
                throw new RuntimeException("Database error:" + ex.getMessage(),ex);
            }
        }
    
    }

The keycloak can read the custom provider when I put the jar in the relevant path. I can also see keycloak is showing all the imported users from this new database, however, I get the following exception in keycloak logs, while the code is trying to compare the passwords.

2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) RS org.postgresql.jdbc.PgResultSet@75dadacb
2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) Password coming from query :: $2a$12$rrtl/vDlCCF0cK0aKu5H6uW30B4fp9cIrTQlHPMayQTR9ToZicEoW
2022-06-24 15:53:30,566 INFO  [com.test.spi.provider.CustomUserStorageProvider] (executor-thread-2) Password coming from user input :: test
2022-06-24 15:53:30,567 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-2) Uncaught server error: java.lang.NoClassDefFoundError: org/springframework/security/crypto/password/PasswordEncoder
        at com.test.spi.provider.CustomUserStorageProvider.isValid(CustomUserStorageProvider.java:147)
        at org.keycloak.credential.UserCredentialStoreManager.lambda$validate$4(UserCredentialStoreManager.java:164)
        at java.base/java.util.Collection.removeIf(Collection.java:576)
        at org.keycloak.credential.UserCredentialStoreManager.validate(UserCredentialStoreManager.java:164)
        at org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:151)
        at org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:110)
        at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.validatePassword(AbstractUsernameFormAuthenticator.java:229)
        at org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator.validateUserAndPassword(AbstractUsernameFormAuthenticator.java:150)
        at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.validateForm(UsernamePasswordForm.java:55)
        at org.keycloak.authentication.authenticators.browser.UsernamePasswordForm.action(UsernamePasswordForm.java:48)
        at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:169)
        at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:990)
        at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:321)
        at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:292)
        at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:276)
        at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:349)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
        at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:71)
        at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
        at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
        at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassNotFoundException: org.springframework.security.crypto.password.PasswordEncoder
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:107)
        at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:57)
        ... 65 more

I also tried adding PasswordEncoder as Bean in startup application and added it as Autowired dependency in CustomUserStorageProvider class but I get the same exception.

Approach 2 :

@SpringBootApplication
public class SpiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpiApplication.class, args);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

-----
@Service
public class CustomUserStorageProvider implements UserStorageProvider, 
  UserLookupProvider,
  CredentialInputValidator,
  UserQueryProvider {

    @Autowired
    PasswordEncoder enc ;

My pom.xml dependencies are here :

<dependencies>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
</dependency>

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-core</artifactId>
    <version>18.0.0</version>
    
</dependency>

<!-- User Storage SPI dependency -->
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-server-spi</artifactId>
    <version>18.0.0</version>
    </dependency>

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-server-spi</artifactId>
    <version>18.0.0</version>
</dependency>
<build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.2.4</version>
                </plugin>
            </plugins>
        </pluginManagement>

        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>

<shadedArtifactAttached>true</shadedArtifactAttached>
                    </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

I am using this command to generate the jar file and keep it inside keycloak-18.0.0/providers/ package.

mvn package

Please assist me with the correct approach. I have gone through several blog posts and questions on this forum as well, but have not obtained the proper solution. TIA.

Main issue:
I even setup this project in eclipse and tried exporting the project as jar file (runnable jar/jar both). The far jar generated is huge in size. 32 MBs instead of 16KBs created by shade plugin but the exception remains the same. Why is this dependency not getting added in the classpath of the jar? I cannot make the 3rd party application using this jar add the classpath, so it has to be embedded inside the final jar. Please help. I have spend a lot of time and I am running out to new workarounds to even try.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

隔纱相望 2025-02-17 15:42:08

值得庆幸的是,我找到了这篇文章,对我有用。

https:// github。 com/keycloak/keycloak/esseage/10230

要总结,

  1. 添加范围为提供的 for keycloak,login,postgres或keycloak可能已经拥有的任何依赖项。这就是我更新的Maven的样子,

    org.keycloak
    KeyCloak-Server-Spi
    $ {keycloak.version}
    假如

    org.postgresql
    Postgresql
    42.3.6
    假如

     &lt; depentency&gt;
        &lt; groupid&gt; org.slf4j&lt;/groupid&gt;
        &lt; artifactid&gt; slf4j-api&lt;/artifactid&gt;
        &lt;版本&gt; 1.7.36&lt;/version&gt;
        &lt; scope&gt;提供&lt;/scope&gt;
    &lt;/depentency&gt;
    
    &lt;依赖关系&gt;
        &lt; groupId&gt; org.springframework.security&lt;/groupid&gt;
        &lt; artifactid&gt; spring-security-crypto&lt;/artifactid&gt;
        &lt;版本&gt; 5.7.1&lt;/version&gt;
    &lt;/depentency&gt;
     
  2. 使用Maven Assembly插件并使用以下命令执行它。该。命令: MVN清洁编译组件:单


插件:

 <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <finalName>my-user-provider</finalName>
                <appendAssemblyId>false</appendAssemblyId>
            </configuration>
        </plugin>
    </plugins>
</build>

上面的2个修改,修复了我的东西。

Thankfully I found this post and it worked for me.

https://github.com/keycloak/keycloak/issues/10230

To summarize,

  1. Add scope as provided for keycloak, login, Postgres, or any dependencies which keycloak might already have. This is how my updated maven looks like,

    org.keycloak
    keycloak-server-spi
    ${keycloak.version}
    provided

    org.postgresql
    postgresql
    42.3.6
    provided

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.36</version>
        <scope>provided</scope>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-crypto</artifactId>
        <version>5.7.1</version>
    </dependency>
    
  2. Utilize the maven assembly plugin and execute it using the below command. Helpful post for that another answer. Command : mvn clean compile assembly:single

Plugin :

 <build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <finalName>my-user-provider</finalName>
                <appendAssemblyId>false</appendAssemblyId>
            </configuration>
        </plugin>
    </plugins>
</build>

Above 2 modifications, repaired my thing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文