网页如何基于java_java-如何与使用keycloak提供网页的客户端一...

我正在使用Spring Boot和Keycloak开发一个Web应用程序.

然后,我编写了一个计划任务,在其中使用KeycloakRestTemplate向另一个应用程序询问一些数据,如下所示:

@Override

@Scheduled(cron="0 50 09 * * MON-FRI")

public void concludiCommessa() {

try {

FDto[] ftts = new ObjectMapper().readValue(restTemplate.getForEntity(URI.create(MY_URL), String.class).getBody(), FDto[].class);

..............................

}

} catch (RestClientException | IOException e) {

}

}

如果在服务器上运行它,则会出现以下错误:

2018-04-18 09:50:00.067 ERROR 2503 --- [pool-8-thread-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task.

java.lang.IllegalStateException: Cannot set authorization header because there is no authenticated principal

at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.getKeycloakSecurityContext(KeycloakClientRequestFactory.java:70) ~[keycloak-spring-security-adapter-3.4.2.Final.jar:3.4.2.Final]

at org.keycloak.adapters.springsecurity.client.KeycloakClientRequestFactory.postProcessHttpRequest(KeycloakClientRequestFactory.java:55) ~[keycloak-spring-security-adapter-3.4.2.Final.jar:3.4.2.Final]

at org.springframework.http.client.HttpComponentsClientHttpRequestFactory.createRequest(HttpComponentsClientHttpRequestFactory.java:207) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:85) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:656) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:636) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:336) ~[spring-web-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at it.edile.service.api.ApiServiceImpl.concludiCommessa(ApiServiceImpl.java:287) ~[classes/:0.0.1-SNAPSHOT]

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_161]

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_161]

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_161]

at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_161]

at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.3.14.RELEASE.jar:4.3.14.RELEASE]

at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_161]

at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_161]

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_161]

at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_161]

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_161]

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_161]

at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]

为什么?

如果我正在使用异步任务,如何传递主体?

编辑

这是我的安全配置:

@Autowired

public void configureGlobal(AuthenticationManagerBuilder auth) {

auth.authenticationProvider(keycloakAuthenticationProvider());

}

@Bean

@Override

protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {

return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());

}

@Bean

@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)

public KeycloakRestTemplate keycloakRestTemplate() {

return new KeycloakRestTemplate(keycloakClientRequestFactory);

}

@Bean

public KeycloakConfigResolver keycloakConfigResolver() {

return new KeycloakSpringBootConfigResolver();

}

编辑这是我的密钥斗篷属性:

#######################################

# KEYCLOAK #

#######################################

keycloak.realm=MY_REALM

keycloak.auth-server-url=MY_URL/auth

keycloak.ssl-required=external

keycloak.resource=EdilGest

keycloak.credentials.jwt.client-key-password=PWD

keycloak.credentials.jwt.client-keystore-file=classpath:CLIENT.jks

keycloak.credentials.jwt.client-keystore-password=PWD

keycloak.use-resource-role-mappings=true

keycloak.principal-attribute=preferred_username

编辑:

我必须发送如下请求:

POST /auth/realms/demo/protocol/openid-connect/token

Authorization: Basic cHJvZHVjdC1zYS1jbGllbnQ6cGFzc3dvcmQ=

Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials

密钥斗篷,但是如何使用Spring发送呢?以及如何设置jks而不是客户端和机密?

编辑2

我的安全配置

@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled=true)

@KeycloakConfiguration

public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

@Autowired

public KeycloakClientRequestFactory keycloakClientRequestFactory;

@Override

protected void configure(HttpSecurity http) throws Exception {

super.configure(http);

http

.httpBasic()

.disable();

http

.authorizeRequests()

.antMatchers("/webjars/**").permitAll()

.antMatchers("/resources/**").permitAll()

.anyRequest().hasAuthority("......")

.and()

.logout()

.logoutUrl("/logout")

.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))

.permitAll()

.logoutSuccessUrl(mux)

.invalidateHttpSession(true);

}

@Autowired

public void configureGlobal(AuthenticationManagerBuilder auth) {

auth.authenticationProvider(keycloakAuthenticationProvider());

}

@Bean

@Override

protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {

return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());

}

@Bean

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

public KeycloakRestTemplate keycloakRestTemplate() {

return new KeycloakRestTemplate(keycloakClientRequestFactory);

}

@Bean

public KeycloakConfigResolver keycloakConfigResolver() {

return new KeycloakSpringBootConfigResolver();

}

@Bean

public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter filter) {

FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);

registrationBean.setEnabled(false);

return registrationBean;

}

@Bean

public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(KeycloakPreAuthActionsFilter filter) {

FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);

registrationBean.setEnabled(false);

return registrationBean;

}

@Override

public void configure(WebSecurity web) throws Exception {

web

.ignoring()

.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/webjars/**");

}

}

编辑3

在这里,我尝试了…它不起作用..我遇到相同的错误:java.lang.IllegalStateException:无法设置授权标头,因为没有经过身份验证的主体

KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("EdilGest.jks"), "EdilGest".toCharArray());

JWTClientCredentialsProvider jwtClientCredentialsProvider = new JWTClientCredentialsProvider();

jwtClientCredentialsProvider.setupKeyPair(keyStoreKeyFactory.getKeyPair("MyClient"));

String token = jwtClientCredentialsProvider.createSignedRequestToken("MyClient", "http://myKeycloak/auth/");

String data = "grant_type=client_credentials" ;

HttpHeaders headers = new HttpHeaders();

headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

headers.add(HttpHeaders.AUTHORIZATION, "Bearer " +token);

HttpEntity requestEntity = new HttpEntity(data, headers);

String ftt = keycloakRestTemplate.exchange(URI.create(MyUrl), HttpMethod.POST, requestEntity, String.class).getBody();

我究竟做错了什么?

很抱歉,我之前提到的 `tokenManager().grantRefreshToken(refreshToken)` 是一个伪代码示例,实际上 KeycloakJava 客户端库中并没有这个方法。请忽略我之前的回答。 要通过 Keycloak 使用 Refresh Token 获取 Access Token,你可以使用 Keycloak 的 Rest API 或者其他 HTTP 客户端库来发送请求。以下是一个使用 Java 的 `HttpClient` 类来发送请求的示例代码: ```java import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.HashMap; import java.util.Map; public class KeycloakClientExample { public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException { // Keycloak 配置信息 String serverUrl = "http://localhost:8080/auth"; String realm = "your-realm"; String clientId = "your-client"; String clientSecret = "your-client-secret"; String refreshToken = "your-refresh-token"; // 构建请求参数 Map<String, String> params = new HashMap<>(); params.put("grant_type", "refresh_token"); params.put("refresh_token", refreshToken); params.put("client_id", clientId); params.put("client_secret", clientSecret); // 构建请求 HttpRequest request = HttpRequest.newBuilder() .uri(new URI(serverUrl + "/realms/" + realm + "/protocol/openid-connect/token")) .header("Content-Type", "application/x-www-form-urlencoded") .POST(buildFormDataFromMap(params)) .build(); // 发送请求 HttpClient client = HttpClient.newHttpClient(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); // 检查响应 if (response.statusCode() == 200) { String responseBody = response.body(); System.out.println("Access Token Response: " + responseBody); } else { System.out.println("Failed to retrieve Access Token"); } } private static HttpRequest.BodyPublisher buildFormDataFromMap(Map<String, String> data) { StringBuilder builder = new StringBuilder(); for (Map.Entry<String, String> entry : data.entrySet()) { if (builder.length() > 0) { builder.append("&"); } builder.append(entry.getKey()); builder.append("="); builder.append(entry.getValue()); } return HttpRequest.BodyPublishers.ofString(builder.toString()); } } ``` 确保在运行代码之前,将上述示例中的配置信息替换为你自己的实际值。此示例使用Java 11 中引入的 `java.net.http.HttpClient` 类来发送 HTTP 请求。 请注意,此示例仅用于演示目的,实际应用中可能需要添加错误处理、合适的认证方法以及其他安全措施。你可以根据自己的需求和使用的 HTTP 客户端库进行相应的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值