我想创建一个可通过以下方式工作的Web服务:
客户端污染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步:访问受保护的Web服务
该Web服务在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的登录页面,而不是Web服务的响应。
如何配置Web服务?
这是实际的Web服务:
@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/*
要获得“你好,世界!”,我需要更改什么?发送标有访问令牌的请求时响应如何?
更新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
答案 0 :(得分:0)
您使用了不正确的流或目的地。如果您想使用登录名/密码,则可以选择其中两个:
电流。您尝试访问,服务器检查您的登录名,如果不是,请-重定向到keycloak。登录后,keycloak使用访问码(不是令牌)将您重定向到您的页面(或登录页面,我不记得了)。之后,您的服务会将此代码发送到keycloak并执行其他操作
将流程更改为密码流程。在这种情况下,您会将用户名/密码发送到您的服务(而不是Keycloak),您的服务将此凭据发送到Keycloak,然后再做其他事情
更新:
我更喜欢让用户使用第一本书,但是如果您需要通过其他程序登录,则最好使用其他机制。 ClientCredentials
或角色范围小的自定义用户
UPDATE2:
如果您确实需要使用身份验证令牌,则可以实现自定义AccessTokenProvider并使用UserInfoRestTemplateCustomizer自定义OAuth2RestTemplate
。但这并不容易