如何使用 keycloak 和 spring 读取所有用户?

2024-01-13

我在用着keycloak 3.4 and spring boot开发一个网络应用程序。 我使用 Active Directory 作为用户联合来检索所有用户信息。

但要在我的网络应用程序中使用这些信息,我想我必须将它们保存在“local-webapp”数据库​​中。

那么用户登录后,如何将它们保存到数据库中呢?

我正在考虑一个scenario比如:“我有一个对象 A,它引用用户 B,所以我必须在它们之间建立关系。所以我添加一个外键。”

在这种情况下,我需要让用户访问我的数据库。不?

EDIT

为了避免将所有用户保存在我的数据库上,我尝试使用管理员 API,因此我在控制器中添加了以下代码。

我还创建了另一个客户端,名为Test为了获得所有用户,这样我可以使用client-id and 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

我哪里做错了?

EDIT 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. Why?

EDIT 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();
     }
     
}

EDIT 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

EDIT 5.

This is my keycloak config: enter image description here

the user that I'm using to login with view user permission: enter image description here

EDIT 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]

为了访问整个用户列表,您必须验证已登录的用户至少包含view-users角色来自realm-management客户,请参阅这个答案 https://stackoverflow.com/a/46558530/1199132我前段时间写过。一旦用户拥有此角色,她检索到的 JWT 将共同包含该角色。

从你的评论中我可以推断,你似乎缺乏一些关于Authorization标头。用户登录后,她会从 keycloak 获取签名的 JWT,因此领域中的每个客户端都可以信任它,而无需询问 Keycloak。该 JWT 包含访问令牌,稍后在Authorization每个用户请求的标头,前缀为Bearer关键字(参见基于令牌的身份验证 in https://auth0.com/blog/cookies-vs-tokens-definitive-guide/ https://auth0.com/blog/cookies-vs-tokens-definitive-guide/).

因此,当用户向您的应用程序发出请求以查看用户列表时,她的访问令牌包含view-users角色已经进入请求标头。不必手动解析它,而是自己创建另一个请求来访问 Keycloak 用户端点并附加它(就像您似乎正在做的那样)KeycloakBuilder),Keycloak Spring Security 适配器已经提供了KeycloakRestTemplate类,它能够为当前用户执行对另一个服务的请求:

安全配置.java

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    ...

    @Autowired
    public KeycloakClientRequestFactory keycloakClientRequestFactory;

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public KeycloakRestTemplate keycloakRestTemplate() {
        return new KeycloakRestTemplate(keycloakClientRequestFactory);
    }

    ...
}

请注意,模板的范围是PROTOTYPE,因此 Spring 将为每个发出的请求使用不同的实例。

然后,自动装配此模板并使用它来发出请求:

@Service
public class UserRetrievalService{

    @Autowired
    private KeycloakRestTemplate keycloakRestTemplate;

    public List<User> getUsers() {
        ResponseEntity<User[]> response = keycloakRestTemplate.getForEntity(keycloakUserListEndpoint, User[].class);
        return Arrays.asList(response.getBody());
    }

}

您需要实施自己的User与 keycloak 服务器返回的 JSON 响应相匹配的类。

请注意,当用户不允许访问该列表时,Keycloak 服务器会返回 403 响应代码。您甚至可以在自己之前否认它,使用一些注释,例如:@PreAuthorize("hasRole('VIEW_USERS')").

最后但并非最不重要的一点是,我认为@dchrzascik 的回答很明确。总而言之,我想说实际上还有另一种方法可以避免每次从 keycloak 服务器检索整个用户列表或将用户存储在应用程序数据库中:您实际上可以缓存它们,这样您就可以更新该缓存从您的应用程序进行用户管理。


EDIT

我已经实现了一个示例项目来展示如何获取完整的用户列表,并将其上传到Github https://github.com/xtremebiker/keycloak-user-retrieval。它是为机密客户端配置的(当使用公共客户端时,应从 application.properties 中删除机密)。

也可以看看:

  • https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/java/spring-security-adapter.adoc https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/java/spring-security-adapter.adoc
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 keycloak 和 spring 读取所有用户? 的相关文章

随机推荐

  • 为什么我的重绘不起作用?

    考虑到扩展了 Canvas 的 Display 类 我遇到了一个问题 单个线程在同一个类中运行 在这个线程中 调用了repaint方法 然而 虽然线程工作正常 但油漆方法从未被调用 这是我的代码 我遗漏了所有不相关的内容 package d
  • 可以修改字典值。正确的方法是什么?

    我有已填充的字典 但我无法控制 我需要修改该值我该怎么做 我举了一个例子来解释这个问题 class Program static void Main string args Dictionary
  • 在二维数组上查找第 K 个最小元素(或中值)的最快算法?

    我看到很多相关主题的 SO 主题 但没有一个提供有效的方法 我想找到k th二维数组上的最小元素 或中值 1 M 1 N 其中每行按升序排序 并且所有元素都是不同的 我认为有O M log MN 解决方案 但我不知道实施 中位数的中位数或使
  • 在 pyjade 解决方法中包含 mixin

    正如github问题中提到的 70 https github com SyrusAkbary pyjade issues 70包括 mixins 不受支持 有什么好的解决方法或替代解决方案吗 Pyjade 的 include 实现不支持 m
  • 为 python 项目构建一个wheel/egg以及所有依赖项

    为了在我们公司内部署 python 项目 我需要制作一个可安装的发行版 这应该包括 为我的项目提供一个鸡蛋或whl 项目的每个依赖项都有一个 Egg 或 WHL 可选 生成一个requirements txt 文件 列出此版本的所有可安装组
  • 如何将cefpython编译为exe

    我在用头孢Python https code google com p cefpython 创建一个简单的基于 HTML5 的应用程序 我正在使用 Python 和 pywin32 绘制一个简单的窗口并在那里渲染框架 我想编译我的 py进入
  • 使用curl循环遍历url的Shell脚本

    我一直在尝试创建一个简单的脚本 该脚本将从 txt 文件中获取查询列表 附加主 url 变量 然后抓取内容并将其输出到文本文件 这是我到目前为止所拥有的 bin bash url example com q for i in cat que
  • main函数中的返回类型可以省略吗? [复制]

    这个问题在这里已经有答案了 对于申报有什么特殊规定吗 main功能 根据ideone http ideone com eEoa8n这是合法的 C main As opposed to int main return 0 另一方面 普通函数似
  • 将属性从 inSequence 传递到 outSequence

    我正在使用代理向 HL7 TCP IP 端口发送消息 并在 outSequence 中获取响应 但我的问题是 inSequence 中设置的所有属性都不再可用 它们全部为空 我测试了所有不同的范围 传输 axis2 axis2 client
  • Android Eclipse 项目上 Assets 文件夹中的自己的数据库

    我的 Android 应用程序有一个大问题 我第一次使用 sqlite 数据库开发 Android 应用程序 但我遇到了无法解决的问题 我的 sqlite 数据库位于 eclipse 项目的资产文件夹中 名称为 saldb sqlite 我
  • 窗口在所有空间(包括其他全屏应用程序)上可见

    我正在尝试使窗口 NSWindow 在所有空间 包括其他全屏应用程序窗口 上可见 我一直在尝试设置更高的窗口级别以及在检查器中使用曝光和空间设置 我在这里找到了一些解决方案 但它们不起作用 至少在酋长岩是这样 这是要测试的示例代码 let
  • 检查Firestore中的任何文档是否包含子字符串[重复]

    这个问题在这里已经有答案了 我在 Firestore 中收集了大量具有随机 ID 的文档 每个文档都有两个字段 名称和描述 我希望我的应用程序允许用户输入一系列字符 然后向他展示包含该字符序列 例如名称字段 的所有文档 使用 Firebas
  • 机器学习回归模型预测每张图像的相同值

    我目前正在开展一个项目 涉及训练回归模型 保存它 然后加载它以使用该模型进行进一步的预测 但是我有一个问题 每次我对图像进行 model predict 时 它都会给出相同的预测 我不完全确定问题是什么 也许是在训练阶段 或者我只是做错了什
  • WPF8/C# - 将数据绑定到网格

    我知道我发布了这个问题 但是在接受了上一个问题的答案并阅读本文后 我意识到这不是我正在寻找的答案 我再次发布了一些示例代码 我想用集合中的数据填充网格 不是数据网格 这是我所拥有的 但它不起作用 如果我删除集合并将 DataContext
  • GridLayoutManager 自定义

    i want to know if there is way that i can customize gridlayoutmanager in android to have horizontal layout like this ske
  • Jquery UI 对话框追加到 Div

    我正在使用下面的代码创建一个 Jquery UI 对话框 var dynDiv document createElement div document getElementById divparent appendChild dynDiv
  • 传递不同类型的可变数量的参数 - C++

    我正在使用 C 进行编码 并且有一些关于省略号的问题 是否可以将类或类指针传递到省略号中 基本上我想做的是以以下类型传递可变数量的参数char and class 我目前正在使用省略号 并试图找出如何通过课堂 如果省略号在这里不适用 有哪些
  • 跨不同域和不同应用程序共享 cookie(经典 ASP 和 ASP.NET)

    有没有办法跨不同域和不同应用程序 经典 ASP 和 ASP NET 共享 cookie 不 没有 问题是跨域问题 而不是 asp net classic asp 并且是安全原因 如果域是子域 您可以共享 cookie 前提是您使用双方都可以
  • VSCode 中 jupyter 笔记本中的交互式 python 3d 绘图

    When I use jupyter notebook in Chrome I had the opportunity to show interactive 3d plots like this 现在我想在 VSCode 中看到相同的结果
  • 如何使用 keycloak 和 spring 读取所有用户?

    我在用着keycloak 3 4 and spring boot开发一个网络应用程序 我使用 Active Directory 作为用户联合来检索所有用户信息 但要在我的网络应用程序中使用这些信息 我想我必须将它们保存在 local web