Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在jar文件中添加外部JAR依赖项

在jar文件中添加外部JAR依赖项
EN

Stack Overflow用户
提问于 2022-06-24 04:05:18
回答 1查看 418关注 0票数 0

Backgorund :我试图为我的遗留应用程序添加UserStorageSPI,这样我们就可以使用现有的用户凭据登录。我遵循了这个教程,示例应用程序的完整源代码是可用的这里

此应用程序存储明文密码并直接对它们进行比较。但是,我的旧数据库以加密格式存储密码。为了测试一个示例用户,我以bcrypt格式存储凭证,并在我的CustomUserStorageProvider类中重写了以下方法(isValid(.))。

方法1:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);
            }
        }
    
    }

当我将jar放入相关路径时,keycloak可以读取自定义提供程序。我还可以看到keycloak显示了从这个新数据库导入的所有用户,但是,我在keycloak日志中得到了以下异常,同时代码试图比较密码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@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依赖项在这里:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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-18.0.0/providers/ package中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mvn package

请用正确的方法帮助我。我在这个论坛上也经历过几个博客文章和问题,但没有得到适当的解决办法。蒂娅。

主要问题:我甚至在eclipse中安装了这个项目,并尝试将项目导出为jar文件(runnable /jar都是)。产生的远罐子体积很大。32 MBs,而不是16 of创建的阴影插件,但例外保持不变。为什么这个依赖项没有被添加到jar的类路径中?我不能使用这个jar让第三方应用程序添加类路径,所以它必须嵌入到最后一个jar中。请帮帮忙。我已经花了很多时间,我已经用尽了新的解决办法,甚至尝试。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-28 04:53:01

谢天谢地,我找到了这篇文章,它对我起了作用。

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

总之,

  1. 为密钥披风、登录、Postgres或键斗篷可能已经具有的任何依赖项添加范围为provided。这就是我更新后的maven的样子, org.keycloak keycloak-server-spi ${keycloak.version}提供org.postgresql postgresql 42.3.6提供org.slf4j slf4j-api 1.7.36提供org.springframework.security spring-安全-加密5.7.1
  2. 利用maven程序集插件并使用以下命令执行它。这篇文章对另一个答案有帮助。命令:mvn clean compile assembly:single

插件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <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项修改,修复了我的东西。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72743821

复制
相关文章
Swift入门:闭包
到目前为止,您已经遇到了整数、字符串、双精度数、浮点数、布尔值、数组、字典、结构和类,但是还有另一种类型的数据在Swift中广泛使用,它被称为闭包。这些是复杂的,但它们是如此强大和富有表现力,它们在 Cocoa Touch 广泛使用,所以如果你不了解他们,你不会走得很远。
韦弦zhy
2020/03/19
5490
Swift学习:闭包
本篇将详细总结介绍Swift闭包的用法; 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift中的闭包与C和 Objective-C中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。
梧雨北辰
2018/08/09
8610
Swift之闭包
Swift 是一门由Apple 公司开发的用于iOS和OSX设备上的开发语言,吸收了很多现代开发语言的优势。 今天看了官方的关于闭包部分的文档,感觉很不错,记录一下。
EltonZheng
2021/01/26
1.7K0
使用 Swift Package Manager 创建 Swift 包
image.png Using the Package Manager 官网 https://swift.org/getting-started/#using-the-package-manager 进入准备创建 Swift 包文件位置 image.png 创建新的Swift包,首先要创建并输入一个名为的目录 perfect-Qiniu: image.png 进入刚才创建的 perfect-Qiniu 文件
LeeCen
2018/10/11
1.4K0
使用 Swift Package Manager 创建 Swift 包
Swift教程(七)--闭包
闭包是可以在你的代码中被传递和引用的功能性独立模块。Swift 中的闭包和 C 以及 Objective-C 中的 blocks 很像,还有其他语言中的匿名函数也类似。
roc
2019/07/31
7710
Swift系列八 - 闭包
要想使用exec函数,则必须传入两个Int类型的参数和一个返回Int类型的函数,然后exec内部执行了传入的函数。
呆呆
2021/05/27
4300
Swift-闭包(一)
array.sort{(n1:Int,n2:Int) -> Bool in return n1<n2}
Wilbur-L
2021/03/18
4460
swift的闭包结构
函数的设计思路是将有一定功能的代码块包装在一起,通过函数名实现复用。闭包和函数有着类似的作用,然而闭包的设计大多数情况下并不是为了代码的复用,而是传递功能代码块和处理回调结构。 如下代码所示,使用了冒泡排序算法来进行排序操作。 func mySort(array:inout Array<Any>,sortClosure:(Int,Int)->Bool)->Array<Any> { for indexI in array.indices {
用户2554571
2018/07/19
5630
Swift中的闭包(Closures)
闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。
EltonZheng
2021/01/22
2K0
苹果现已支持 Swift 包索引
作者 | Sergio De Simone 译者 | 马可薇 策划 | 丁晓昀 Dave Verwer 和 Sven A. Schmidt 于三年前(2019 年)创建了 Swift 包索引,目的为让 Swift 开发者能够轻松地搜索发现 Swift 包。目前该项目已正式获得苹果的赞助,使其成为 Swift 包相关事宜的官方网站。 顾名思义,Swift 包索引并不是完整的软件包仓库,而是专注于为软件包元数据编制索引,为开发者们在决定项目要使用的软件包时提供其完善的信息。 其所能回答的问题包括:某个
深度学习与Python
2023/04/21
4520
苹果现已支持 Swift 包索引
Swift 基于闭包的类型擦除
与许多其他语言相比,使Swift更加安全,更不易出错的原因之一是其先进的(并且在某种程度上是不容忍的)类型系统。这是一种语言功能,有时可能会给人留下深刻的印象,使您的工作效率提高很多,而有时却令人沮丧。
Swift社区
2021/11/26
1.2K0
【Swift4】(6) 闭包 | 闭包应用 | 闭包作为函数参数 | 捕获特性
前端修罗场
2023/10/07
1930
Swift 闭包支持隐式 self
在 closure 捕获列表中,如果显式捕获self,则在 closure 使用时,则允许隐式使用self。即在 closure 捕获列表中声明[self], 则 closure 内调用self.的地方都可以不用书写该self.。这个特性在SE-0269中提议。现在本篇提议想把这个特性支持扩展到weak self的捕获上,并允许隐式self和已解包的self一样使用。效果就是如果在 closure 内 self 已经解包,则 closure 内调用 self 的地方可以不用写 self。如下例的dismiss方法调用:
DerekYuYi
2022/11/09
1.4K0
Swift-day4---闭包(Closures)
闭包写在一对大括号中,用 "in"关键字分隔,"in"后的语句是闭包的主体."in"之前的参数和返回值类型是语句组中所使用的参数和返回值格式的一种指示,并不必在语句组中进行逻辑运算和返回.闭包的表达式的运算结果是一种函数类型,可以作为表达式,函数参数和函数返回值
CC老师
2023/03/23
6310
Swift-day4---闭包(Closures)
包资源管理器NPM
NPM全称Node Package Manager,他是node包管理和分发工具。其实我们可以把NPM理解为前端的Maven .
名字是乱打的
2021/12/22
9650
Swift 基于闭包的类型擦除
与许多其他语言相比,使Swift更加安全,更不易出错的原因之一是其先进的(并且在某种程度上是不容忍的)类型系统。这是一种语言功能,有时可能会给人留下深刻的印象,使您的工作效率提高很多,而有时却令人沮丧。
韦弦zhy
2021/06/11
1.1K0
Swift 基于闭包的类型擦除
Swift讲解专题八——闭包 原
        Swift中的闭包是有一定功能的代码块,这十分类似于Objective-C中的block语法。Swift中的闭包语法风格十分简洁,其作用和函数的作用相似。
珲少
2018/08/15
3860
Swift进阶六——函数和闭包
形式参数,指的是是在函数的定义中,系统并没有为其分配内存空间、但是在函数里面可以使用的参数。比如下面的a就是形式参数:
拉维
2021/01/21
1.2K0
Swift3.0 - 函数和闭包
需求: 创建一个接口,输入true 返回 两个数相加的函数,输入false 返回两个数相减的函数
酷走天涯
2018/09/14
1.1K0
Swift3.0 - 函数和闭包
paletteer包:拥有2100多个调色板!
ggplot2是目前主流的绘图R包,有着丰富的扩展包。今天来推荐一个极其强大的配色R包——paletteer包。据R包作者介绍,这个包收集了52个R包的2100种调色板,R用户可以通过paletteer[1]包来直接调用其他R包的调色板。下面来学习下怎么使用这个R包[2]。
庄闪闪
2021/06/25
8.2K0
paletteer包:拥有2100多个调色板!

相似问题

类型标命名

12

类型标重命名类型

12

为命名空间类型标赋值

12

类型标全局命名空间声明

13

webpack的类型标命名空间

19
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文