带有 Keycloak 的 SpringBoot OAuth2 不返回映射的角色作为权限

2024-01-06

我正在创建一个简单的 SpringBoot 应用程序并尝试与 OAuth 2.0 提供程序 Keycloak 集成。我在领域级别创建了领域、客户端、角色(成员、PremiumMember),最后创建了用户并分配了角色(成员、PremiumMember)。

如果我使用Keycloak提供的SpringBoot Adapterhttps://www.keycloak.org/docs/latest/secure_apps/index.html#_spring_boot_adapter https://www.keycloak.org/docs/latest/securing_apps/index.html#_spring_boot_adapter然后,当我成功登录并检查登录用户的权限时,我可以看到分配的角色,例如会员、高级会员。

Collection<? extends GrantedAuthority> authorities = 
 SecurityContextHolder.getContext().getAuthentication().getAuthorities();

但是,如果我使用通用 Spring Boot Oauth2 客户端配置,我可以登录,但是当我检查权限时,它总是只显示ROLE_USER、SCOPE_电子邮件、SCOPE_openid、SCOPE_个人资料并且不包括我映射的角色(会员、高级会员)。

我的 Spring Boot OAuth2 配置:

pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

应用程序属性

spring.security.oauth2.client.provider.spring-boot-thymeleaf-client.issuer-uri=http://localhost:8181/auth/realms/myrealm

spring.security.oauth2.client.registration.spring-boot-thymeleaf-client.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.spring-boot-thymeleaf-client.client-id=spring-boot-app
spring.security.oauth2.client.registration.spring-boot-thymeleaf-client.client-secret=XXXXXXXXXXXXXX
spring.security.oauth2.client.registration.spring-boot-thymeleaf-client.scope=openid,profile,roles
spring.security.oauth2.client.registration.spring-boot-thymeleaf-client.redirect-uri=http://localhost:8080/login/oauth2/code/spring-boot-app

我在用春季启动2.5.5 and 钥匙斗篷 15.0.2.

使用这种通用的 OAuth2.0 配置方法(不使用 Keycloak SpringBootAdapter)有没有办法获取分配的角色?


默认情况下,Spring Security 会生成一个列表GrantedAuthority使用中的值scope or scp索赔和SCOPE_ prefix.

Keycloak 将领域角色保留在嵌套声明中realm_access.roles。您有两种选择来提取角色并将其映射到列表GrantedAuthority.

OAuth2客户端

如果您的应用程序配置为 OAuth2 客户端,则您可以从 ID 令牌或 UserInfo 端点提取角色。 Keycloak 仅在访问令牌中包含角色,因此您需要更改配置以将它们也包含在 ID 令牌或 UserInfo 端点中(这就是我在以下示例中使用的)。您可以从 Keycloak 管理控制台执行此操作,转至Client Scopes > roles > Mappers > realm roles

然后,在 Spring Security 配置中,定义一个GrantedAuthoritiesMapper它从 UserInfo 端点提取角色并将它们映射到GrantedAuthoritys。在这里,我将介绍特定 bean 的外观。我的 GitHub 上提供了完整的示例:https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/login-user-authorities https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/login-user-authorities

@Bean
public GrantedAuthoritiesMapper userAuthoritiesMapperForKeycloak() {
        return authorities -> {
            Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
            var authority = authorities.iterator().next();
            boolean isOidc = authority instanceof OidcUserAuthority;

            if (isOidc) {
                var oidcUserAuthority = (OidcUserAuthority) authority;
                var userInfo = oidcUserAuthority.getUserInfo();

                if (userInfo.hasClaim("realm_access")) {
                    var realmAccess = userInfo.getClaimAsMap("realm_access");
                    var roles = (Collection<String>) realmAccess.get("roles");
                    mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
                }
            } else {
                var oauth2UserAuthority = (OAuth2UserAuthority) authority;
                Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes();

                if (userAttributes.containsKey("realm_access")) {
                    var realmAccess =  (Map<String,Object>) userAttributes.get("realm_access");
                    var roles =  (Collection<String>) realmAccess.get("roles");
                    mappedAuthorities.addAll(generateAuthoritiesFromClaim(roles));
                }
            }

            return mappedAuthorities;
        };
    }

Collection<GrantedAuthority> generateAuthoritiesFromClaim(Collection<String> roles) {
        return roles.stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                .collect(Collectors.toList());
}

OAuth2 资源服务器

如果您的应用程序配置为 OAuth2 资源服务器,则您可以从访问令牌中提取角色。在 Spring Security 配置中,定义一个JwtAuthenticationConverterbean 从访问令牌中提取角色并将它们映射到GrantedAuthoritys。在这里,我将介绍特定 bean 的外观。我的 GitHub 上提供了完整的示例:https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/resource-server-jwt-authorities https://github.com/ThomasVitale/spring-security-examples/tree/main/oauth2/resource-server-jwt-authorities

public JwtAuthenticationConverter jwtAuthenticationConverterForKeycloak() {
    Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter = jwt -> {
        Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
        Collection<String> roles = realmAccess.get("roles");
        return roles.stream()
            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
            .collect(Collectors.toList());
    };

    var jwtAuthenticationConverter = new JwtAuthenticationConverter();
    jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);

    return jwtAuthenticationConverter;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带有 Keycloak 的 SpringBoot OAuth2 不返回映射的角色作为权限 的相关文章

  • 位图内存不足错误

    我对这个错误有疑问 我从 URL 制作网站图标解析器 我这样做是这样的 public class GrabIconsFromWebPage public static String replaceUrl String url StringB
  • MongoTemplate upsert - 从 pojo 进行更新的简单方法(哪个用户已编辑)?

    这是一个简单的 pojo public class Description private String code private String name private String norwegian private String en
  • spring data mongodb中如何实现聚合分页

    spring data mongodb中使用mongotemplate或者mongorepository 如何实现聚合的分页 这是对旧帖子的答案 但我会提供答案 以防其他人在搜索类似内容时出现 建立在之前的基础上F rat K K 的解决方
  • 如何比较 Struts 2 中 url 请求参数中的单个字符

    我正在读取具有单个字符的 url 参数 它将是Y or N 我必须写一个条件来检查它是否Y or N并做相应的事情 这是我写的 但似乎不起作用 总是转到其他地方 网址是
  • 将过滤器添加到 Eclipse 中的 Project Explorer

    我想向 Project Explorer 添加一个新的过滤器 以向用户隐藏一些在 Eclipse RCP 应用程序中自动创建的项目 到目前为止我已经找到了两个扩展点 org eclipse ui ide resourceFilters 允许
  • 是否有任何API可以将Microsoft Exchange服务器与Java应用程序集成以进行任务同步?

    我正在尝试将 Java Web 应用程序与 Microsoft Exchange 服务器集成以实现双向日历 即任务 同步 是否有用于此集成的 Java 开源 商业 API 谢谢 文卡特 看一眼j 交易所 http sourceforge n
  • 定期更新 SWT 会导致 GUI 冻结

    Problem 当 GUI 字段定期更新时 SWT 会冻结 我想要一个基于 SWT 的 GUI 其中文本字段的值会定期递增 最初我从单独的线程访问 textField 导致抛出异常 线程 Thread 0 org eclipse swt S
  • 有多少种方法可以将位图转换为字符串,反之亦然?

    在我的应用程序中 我想以字符串的形式将位图图像发送到服务器 我想知道有多少种方法可以将位图转换为字符串 现在我使用 Base64 格式进行编码和解码 它需要更多的内存 是否有其他可能性以不同的方式做同样的事情 从而消耗更少的内存 现在我正在
  • 如何导入 org.apache.commons.lang3.ArrayUtils;进入 Eclipse [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我如何导入 org apache commons lang3 ArrayUtils 将库添加到 Ecl
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • 线程“main”中的异常 java.lang.StackOverflowError

    我有一段代码 但我无法弄清楚为什么它在线程 main java lang StackOverflowError 中给出异常 这是问题 Given a positive integer n prints out the sum of the
  • Intellij 中的 Google OR-Tools:UnsatisfiedLinkError

    我正在建立一个应该使用 Google OR Tools 的 java 框架 下面的代码编译成功 但在运行时抛出异常 Exception in thread main java lang UnsatisfiedLinkError com go
  • 创建正则表达式匹配数组

    在Java中 我试图将所有正则表达式匹配返回到一个数组 但似乎您只能检查模式是否匹配某些内容 布尔值 如何使用正则表达式匹配来形成与给定字符串中的正则表达式匹配的所有字符串的数组 4城堡的回答 https stackoverflow com
  • 改变for循环的顺序?

    我遇到一种情况 我需要根据用户输入以不同的顺序循环遍历 xyz 坐标 所以我是 3D 空间中的一个区域 然后是一组像这样的 for 循环 for int x 0 x lt build getWidth x for int y 0 y lt
  • 了解 Spark 中的 DAG

    问题是我有以下 DAG 我认为当需要洗牌时 火花将工作划分为不同的阶段 考虑阶段 0 和阶段 1 有些操作不需要洗牌 那么为什么 Spark 将它们分成不同的阶段呢 我认为跨分区的实际数据移动应该发生在第 2 阶段 因为这里我们需要cogr
  • 为什么我的代码会产生错误:该语句没有返回结果集[重复]

    这个问题在这里已经有答案了 我正在从 Microsoft SQL Server Studio 执行以下查询 该查询工作正常并显示结果 SELECT INTO temp table FROM md criteria join WHERE us
  • 使用 JAD 反编译 java - 限制

    我正在尝试使用 Java 中的 JAD 反编译几个 jar 文件 我也尝试过 JD GUI 但运气更差 但出现了很多错误 一种类型 易于修复 似乎是内部类 但我也发现了这段代码 static int SWITCH TABLE atp com
  • 警告:无法更改每个人的权限:

    当运行 Java 快速入门示例时https developers google com drive web quickstart java hl hu https developers google com drive web quicks
  • 春季 CORS。在允许的来源中添加模式

    查看CORS的弹簧指南 以下代码启用所有允许的来源 public class MyWebMVCConfigurer extends WebMvcConfigurerAdapter Override public void addCorsMa
  • 为什么应该首选 Java 类的接口?

    PMD https pmd github io 将举报以下违规行为 ArrayList list new ArrayList 违规行为是 避免使用 ArrayList 等实现类型 而是使用接口 以下行将纠正违规行为 List list ne

随机推荐

  • Swift 委托 - 何时在委托上使用弱指针

    有人可以解释一下何时以及何时不应该对 Swift 中的委托指针使用 弱 赋值 以及为什么 我的理解是 如果您使用未定义为类的协议 您不能也不想将委托指针分配给弱 protocol MyStructProtocol whatever stru
  • bigint 对于事件日志表来说足够大吗?

    现在我知道bigint是2 64 也就是说 比已知宇宙中的原子还要多 我不应该担心 因为我的人类大脑根本无法应对这个数字的巨大 然而 假设我记录了系统中每个类别 产品和订单的每一次更改 从发布到时间结束 在担心主键值用完之前 我是否应该先关
  • 阻止鼠标滚轮事件在 OSX 中发生两次

    我注意到鼠标滚轮事件在 mac osx 中发生了多次 可以归因于惯性特征 有办法解决这种行为吗 自签名 ssl 不用担心 https sandbox idev ge roomshotel html5 v2 https sandbox ide
  • MongoCollectionSettings.GuidRepresentation 已过时,有什么替代方案?

    我正在使用 MongoDB Driver 2 11 0 和 Net Standard 2 1 为了确保数据库存在并且集合存在 我有以下代码 IMongoClient client inject a Mongo client MongoDat
  • 窗口函数:PARTITION BY 一列后 ORDER BY 另一列

    免责声明 显示的问题比我最初预期的要普遍得多 下面的例子取自另一个问题的解决方案 但现在我使用这个示例来解决更多问题 主要与时间序列相关 看看右栏中的 链接 部分 所以我首先尝试更普遍地解释这个问题 我正在使用 PostgreSQL 但我确
  • 替换R中括号内的文本[重复]

    这个问题在这里已经有答案了 可能的重复 删除方括号 圆括号和 或大括号内的文本 https stackoverflow com questions 8621066 remove text inside brackets parens and
  • 如何忽略行长度 PHP_CodeSniffer

    我一直在 jenkins 中使用 PHP CodeSniffer 我的 build xml 是为 phpcs 配置的 如下所示
  • Xcode 中的场景编辑器使用什么单位?

    Xcode 中的场景编辑器显示尺寸但不显示单位 尺寸是以英寸为单位还是以米为单位 例如 当我选择一个节点时 例如一个盒子 当我在节点检查器中检查其属性并在 边界框 旁边的 变换 部分检查其大小时 没有显示任何单位 该单位似乎与 语言和区域
  • Qt 4:移动没有标题栏的窗口

    我有一个Qt Popup带标记的窗口 没有标题栏和关闭等按钮 并且希望通过拖动 单击非标题栏区域来移动 在 Win32 上 解决方案可能是WM NCLBUTTONDOWN http msdn microsoft com en us libr
  • 查找以逗号分隔的列中的所有唯一值

    我通过不同的观察者 观察者组对一个物种进行了多次观察 并希望创建所有独特观察者的列表 我的数据如下所示 data lt read table text species observer 1 A B 1 A B 1 B E 1 B E 1 D
  • safari/chrome/opera 可以在上传过程中发出 ajax 请求吗?

    基本上我正在发出一个简单的ajax请求 function upload setInterval function callMeOften ajax method get url uploadinfo php unique id dataTy
  • Enum.TryParse 的非常基本的使用不起作用

    我发现了一个非常基本的代码 如下所述 但我无法让它在我的 c windows 窗体解决方案中工作 我收到错误 System Enum TryParse string out string 的最佳重载方法匹配有一些无效参数 参数 1 无法从
  • 如何使用 LESS CSS 创建嵌套循环?

    我所知道的是 iterations 8 mixin loop index when index gt 0 my class index width 100 index mixin loop index 1 mixin loop 0 mixi
  • 如何使自定义 MKAnnotation 可拖动

    我需要具有不同引脚图像的 MKAnnotation 所以我创建了以下内容 interface NavigationAnnotation NSObject
  • 如果文件存在,如何增加文件名编号

    如果文件已经存在 如何增加文件名 这是我正在使用的代码 int num 0 String save at getText toString jpg File file new File myDir save if file exists s
  • Firefox 上的 window.open(url) 和 window.location.href = url 有什么区别?

    我正在尝试构建一个书签 将当前 url 作为参数提供给另一个 url 然而我发现这 javascript function window open http www somesi te some thing url encodeURICom
  • 使用索引查找 Pandas 中两个系列之间的交集

    我有两个不同长度的系列 我试图根据索引找到两个系列的交集 其中索引是一个字符串 希望最终结果是一个包含基于公共字符串索引的交集元素的序列 有任何想法吗 Pandas 索引有一个交集法 http pandas pydata org panda
  • Android 方向变化:不同的布局,相同的片段

    这几乎是一个经典的 Android 用例 假设我们有 2 个片段 FragmentS 和 Fragment 在横向模式下 FragmentA 和 FragmentB 并排放置 在纵向模式下 它们在使用时都会占据全屏 See this ima
  • 停止实体框架修改数据库

    我开始尝试实体框架的代码优先方法 主要是这样我可以用注释来装饰我的属性 以便在我的视图中显示 否则 现在我必须创建一个与实体框架为我生成的一个 这样我就可以添加注释 然后将数据从一个对象复制到下一个对象 现在看起来当我启动我的应用程序时它正
  • 带有 Keycloak 的 SpringBoot OAuth2 不返回映射的角色作为权限

    我正在创建一个简单的 SpringBoot 应用程序并尝试与 OAuth 2 0 提供程序 Keycloak 集成 我在领域级别创建了领域 客户端 角色 成员 PremiumMember 最后创建了用户并分配了角色 成员 PremiumMe