Я хочу создать веб-сервис, который будет работать следующим образом:
Клиент подключается к KeyCloak и предоставляет имя пользователя и пароль.
KeyCloak возвращает токен доступа клиенту.
Используя этот токен доступа, клиент получает доступ к странице, защищенной KeyCloak.
Какя могу это сделать?
Что я пробовал
Шаг 1: Клиент получает токен доступа
private String getAccessToken() throws IOException {
final CloseableHttpClient client = HttpClients.createDefault();
final List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("client_id", "test-app"));
nameValuePairs.add(new BasicNameValuePair("username", "user1"));
nameValuePairs.add(new BasicNameValuePair("password", "user1"));
nameValuePairs.add(new BasicNameValuePair("grant_type", "password"));
try {
final HttpPost post = new HttpPost("http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token");
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
post.setHeader("Accept", "application/json");
post.setHeader("Content-type", "application/x-www-form-urlencoded");
final CloseableHttpResponse response = client.execute(post);
final int statusCode = response.getStatusLine().getStatusCode();
System.out.println(String.format("Result: %d", statusCode));
if (statusCode != 200) {
System.out.println("Something went wrong");
return null;
}
final String responseTxt = EntityUtils.toString(response.getEntity());
final JSONObject json = new JSONObject(responseTxt);
final String accessToken = json.getString("access_token");
return accessToken;
} finally {
try {
client.close();
} catch (final IOException exception) {
exception.printStackTrace();
}
}
}
Кажется, это работает, когда я получаю код ответа 200 и токен доступа в теле.
Шаг 2. Доступ к защищенному веб-сервису
Веб-сервис работаетв http://127.0.0.1:8090/test
.
я использую следующий код для доступа к нему (accessToken
- токен доступа из предыдущего шага):
final String targetUrl = "http://127.0.0.1/test";
final CloseableHttpClient client = HttpClients.createDefault();
final HttpGet get = new HttpGet(targetUrl);
get.setHeader("Authorization", String.format("Bearer%s", accessToken));
final CloseableHttpResponse response = client.execute(get);
final int statusCode = response.getStatusLine().getStatusCode();
System.out.println(String.format("Result: %d", statusCode));
client.close();
Когда я это делаю, я получаюстраница входа KeyCloak в качестве ответа, а не ответа веб-службы.
Как настроен веб-сервис?
веб-сервис:
@RestController
public class SampleRestController {
@RequestMapping("/test")
public String test() {
return "Hello, world!";
}
}
Конфигурация безопасности:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider
= keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(
new SessionRegistryImpl());
}
@Override
public void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers("/test*")
.hasRole("user")
.anyRequest()
.permitAll();
}
}
application.properties
:
server.port = 8090
spring.main.allow-bean-definition-overriding=true
keycloak.realm = myrealm
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.ssl-required = external
keycloak.resource = test-app
keycloak.public-client=true
keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/test/*
Что мне нужно изменить, чтобы получить "Hello", Мир!"Ответ, когда я отправляю запрос с токеном доступа в шапке?
Обновление 1: Я обнаружил одну часть проблемы - неправильная конфигурация клиента.Это должно быть bearer only
.
Но теперь я получаю ответ Bearer-only applications are not allowed to initiate browser login
.
Обновление2: При следующей конфигурации службы она работает.
server.port = 8090
spring.main.allow-bean-definition-overriding=true
keycloak.realm = myrealm
keycloak.resource = test-app
keycloak.auth-server-url = http://127.0.0.1:8080/auth
keycloak.bearer-only = true
keycloak.ssl-required = external
keycloak.principal-attribute = preferred_username