我正在使用 keycloak 3.4
和 spring boot
来开发一个网络应用程序。我使用 Active Directory 作为用户联合来检索所有用户信息。
但是要在我的网络应用程序中使用这些信息,我想我必须将它们保存在“local-webapp”数据库中。
那么在用户登录后,如何将它们保存在我的数据库中?
我正在考虑这样的 场景:“我有一个对象 A,它引用用户 B,所以我必须在它们之间建立关系。所以我添加了一个外键。”
在这种情况下,我需要让用户在我的数据库中。不?
编辑
为了避免在我的数据库中保存所有用户,我尝试使用管理员 API,因此我在控制器中添加了以下代码。
我还创建了另一个名为 Test
的客户端来获取所有用户,这样我可以使用 client-id
和 client-secret.
或者有没有办法使用 JWT
使用管理API?
客户端:
Keycloak keycloak2 = KeycloakBuilder.builder()
.serverUrl("http://localhost:8080/auth/admin/realms/MYREALM/users")
.realm("MYREALMM")
.username("u.user")
.password("password")
.clientId("Test")
.clientSecret("cade3034-6ee1-4b18-8627-2df9a315cf3d")
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(20).build())
.build();
RealmRepresentation realm2 = keycloak2.realm("MYREALMM").toRepresentation();
错误是:
2018-02-05 12:33:06.638 ERROR 16975 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.Error: Unresolved compilation problem:
The method realm(String) is undefined for the type AccessTokenResponse
] with root cause
java.lang.Error: Unresolved compilation problem:
The method realm(String) is undefined for the type AccessTokenResponse
我在哪里做错了?
编辑 2
我也试过这个:
@Autowired
private HttpServletRequest request;
public ResponseEntity listUsers() {
KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) request.getUserPrincipal();
KeycloakPrincipal principal=(KeycloakPrincipal)token.getPrincipal();
KeycloakSecurityContext session = principal.getKeycloakSecurityContext();
Keycloak keycloak = KeycloakBuilder.builder()
.serverUrl("http://localhost:8080/auth")
.realm("MYREALMM")
.authorization(session.getToken().getAuthorization().toString())
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(20).build())
.build();
RealmResource r = keycloak.realm("MYREALMM");
List<org.keycloak.representations.idm.UserRepresentation> list = keycloak.realm("MYREALMM").users().list();
return ResponseEntity.ok(list);
但授权始终是 null
。为什么?
编辑 3 以下您可以找到我的 spring 安全配置:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.httpBasic().disable();
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/webjars/**").permitAll()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.logout()
.logoutUrl("/logout")
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.permitAll()
.logoutSuccessUrl("/")
.invalidateHttpSession(true);
}
@Autowired
public KeycloakClientRequestFactory keycloakClientRequestFactory;
@Bean
public KeycloakRestTemplate keycloakRestTemplate() {
return new KeycloakRestTemplate(keycloakClientRequestFactory);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix("ROLE_");
simpleAuthorityMapper.setConvertToUpperCase(true);
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(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(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**", "/webjars/**");
}
@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public AccessToken accessToken() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
return ((KeycloakSecurityContext) ((KeycloakAuthenticationToken) request.getUserPrincipal()).getCredentials()).getToken();
}
}
编辑 4
这些是 applicatoin.properties
#######################################
# KEYCLOAK #
#######################################
keycloak.auth-server-url=http://localhost:8181/auth
keycloak.realm=My Realm
keycloak.ssl-required=external
keycloak.resource=AuthServer
keycloak.credentials.jwt.client-key-password=keystorePwd
keycloak.credentials.jwt.client-keystore-file=keystore.jks
keycloak.credentials.jwt.client-keystore-password=keystorePwd
keycloak.credentials.jwt.alias=AuthServer
keycloak.credentials.jwt.token-expiration=10
keycloak.credentials.jwt.client-keystore-type=JKS
keycloak.use-resource-role-mappings=true
keycloak.confidential-port=0
keycloak.principal-attribute=preferred_username
编辑 5。
编辑 6
这是启用日志记录后的日志表单keycloak:
2018-02-12 08:31:00.274 3DEBUG 5802 --- [nio-8080-exec-1] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/utente/prova4
2018-02-12 08:31:00.274 3DEBUG 5802 --- [nio-8080-exec-1] .k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /utente/prova4
2018-02-12 08:31:00.274 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8080/utente/prova4
2018-02-12 08:31:00.274 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
2018-02-12 08:31:00.275 3DEBUG 5802 --- [nio-8080-exec-1] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/utente/prova4
2018-02-12 08:31:00.275 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8080/utente/prova4
2018-02-12 08:31:00.275 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
2018-02-12 08:31:00.276 3DEBUG 5802 --- [nio-8080-exec-1] o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8080/utente/prova4
2018-02-12 08:31:00.276 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8080/utente/prova4
2018-02-12 08:31:00.276 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
2018-02-12 08:31:10.580 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.s.client.KeycloakRestTemplate : Created GET request for "http://localhost:8181/auth/admin/realms/My%20Realm%20name/users"
2018-02-12 08:31:10.580 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.s.client.KeycloakRestTemplate : Setting request Accept header to [application/json, application/*+json]
2018-02-12 08:31:10.592 3DEBUG 5802 --- [nio-8080-exec-1] o.k.a.s.client.KeycloakRestTemplate : GET request for "http://localhost:8181/auth/admin/realms/My%20Realm%20name/users" resulted in 401 (Unauthorized); invoking error handler
2018-02-12 08:31:10.595 ERROR 5802 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 401 Unauthorized] with root cause
org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:85) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:707) ~[spring-web-4.3.13.RELEASE.jar:4.3.13.RELEASE]
原文由 Teo 发布,翻译遵循 CC BY-SA 4.0 许可协议
为了访问整个用户列表,您必须验证登录的用户至少包含来自
realm-management
客户端的view-users
角色,请参阅我前一段时间写的 这个答案。一旦用户拥有此角色,她检索到的 JWT 将包含它。正如我可以从您的评论中推断的那样,您似乎缺乏一些关于
Authorization
标头的基础。用户登录后,她会从 keycloak 获取签名的 JWT,因此领域中的每个客户端都可以信任它,而无需询问 Keycloak。此 JWT 包含访问令牌,稍后在每个用户请求的Authorization
标头中都需要该令牌,前缀为Bearer
关键字(请参阅 https:// 中 基于令牌的身份验证 auth0.com/blog/cookies-vs-tokens-definitive-guide/ )。因此,当用户向您的应用发出请求以查看用户列表时,她的包含
view-users
角色的访问令牌已经进入请求标头。不必手动解析它,而是自己创建另一个请求来访问 Keycloak 用户端点并附加它(就像您似乎正在使用KeycloakBuilder
所做的那样),Keycloak Spring Security 适配器已经提供了一个KeycloakRestTemplate
类,它能够为当前用户执行对另一个服务的请求:安全配置.java
请注意,模板的范围是
PROTOTYPE
,因此 Spring 将为每个发出的请求使用不同的实例。然后,自动装配此模板并使用它来发出请求:
您将需要实现您自己的
User
与 keycloak 服务器返回的 JSON 响应相匹配的类。请注意,当用户不允许访问该列表时,Keycloak 服务器会返回一个 403 响应代码。您甚至可以在自己面前否认它,使用一些注释,例如:
@PreAuthorize("hasRole('VIEW_USERS')")
。最后但并非最不重要的一点是,我认为@dchrzascik 的回答很明确。总而言之,我想说实际上还有另一种方法可以避免每次从 keycloak 服务器检索整个用户列表或将用户存储在您的应用程序数据库中:您实际上可以缓存它们,因此如果您可以更新该缓存从您的应用程序进行用户管理。
编辑
我已经实现了一个示例项目来展示如何获取上传到 Github 的整个用户列表。它是为机密客户端配置的(使用公共客户端时,应从 application.properties 中删除机密)。
也可以看看: