【问题标题】:Spring Boot Resource Server & Keycloak scope vs. roleSpring Boot 资源服务器和 Keycloak 范围与角色
【发布时间】:2021-02-05 13:08:07
【问题描述】:

有人在使用 Spring Boot 资源服务器和 Keycloak 吗?

我将 application.properties 配置为
spring.security.oauth2.resourceserver.jwt.issuer-uri = http://localhost:9080/auth/realms/<myrealm>

在我的 WebSecurityConfigurerAdapter 中,我可以使用客户端范围,例如 .antMatchers(HttpMethod.GET, "/user/**").hasAuthority("SCOPE_read")

但我无法使用这些角色! .antMatchers(HttpMethod.GET, "/user/**").hasRole("ADMIN")

该信息在 jwt 中可用,但 spring 不知何故不使用它。有人知道我在哪里可以找到描述映射的文档吗? 不知何故,我认为我的脑海中有一个节点,但是在哪里,哪一个?

那是我的 jwt:

  "exp": 1603373908,
  "iat": 1603373608,
  "jti": "0b18b386-9f62-4c42-810e-692ccc4ed7d1",
  "iss": "http://localhost:9080/auth/realms/jhipster",
  "aud": "account",
  "sub": "4c973896-5761-41fc-8217-07c5d13a004b",
  "typ": "Bearer",
  "azp": "web_app",
  "session_state": "17411db5-8d50-4f25-b520-9a3e8b19fd67",
  "acr": "1",
  "allowed-origins": [
    "*"
  ],
  "realm_access": {
    "roles": [
      "test",
      "ROLE_USER",
      "offline_access",
      "ROLE_ADMIN",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  },
  "scope": "email profile",
  "email_verified": true,
  "roles": [
    "test",
    "ROLE_USER",
    "offline_access",
    "ROLE_ADMIN",
    "uma_authorization"
  ],
  "name": "Admin Administrator",
  "preferred_username": "admin",
  "given_name": "Admin",
  "family_name": "Administrator",
  "email": "admin@localhost"
}```

Thanks a lot
Fredy

【问题讨论】:

    标签: spring-boot spring-security keycloak openid-connect spring-oauth2


    【解决方案1】:

    您需要定义一个Converter<Jwt, Collection<GrantedAuthority>>,从 Keycloak 的realm_access 中提取角色(为简洁起见,省略空检查):

    public class KeycloakGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
        @Override
        public Collection<GrantedAuthority> convert(Jwt source) {
            Map<String, Object> realmAccess = source.getClaimAsMap("realm_access");
            List<String> roles = (List<String>) realmAccess.get("roles");
            return roles.stream()
                    .map(rn -> new SimpleGrantedAuthority("ROLE_" + rn))
                    .collect(Collectors.toList());
        }
    }
    

    请注意,这只会提取角色。如果您需要范围角色,请查看 Spring 的默认 JwtGrantedAuthoritiesConverter 以获取代码示例。

    JwtAuthenticationConverter中定义它:

    private JwtAuthenticationConverter jwtAuthenticationConverter() {
        JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
        jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakGrantedAuthoritiesConverter());
        return jwtConverter;
    }
    

    最后在你的 WebSecurityConfigurerAdapter 中使用它:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // [...]
                .oauth2ResourceServer()
                    .jwt()
                    .jwtAuthenticationConverter(jwtAuthenticationConverter());
    }
    

    【讨论】:

      【解决方案2】:

      这可能是由于 Spring Security 从 JWT 令牌中解析/提取角色详细信息的方式。例如,在 MicroProfile 规范中,提到角色列表将从令牌的“组”属性中提取。

      查看 Spring Security 中的 RoleVoter 文档。似乎它希望角色名称专门以 ROLE_ 前缀开头。也许你就是这种情况。

      【讨论】:

        【解决方案3】:

        您没有包含使用的版本,但我遇到了与 spring-security-oauth2-resource-server 5.2.2.RELEASE 相同的问题。 这个方法:

        org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter#getAuthorities
        

        默认负责从 jwt 获取权限。它只检查声明名称scopescp。但是,正如 response 所建议的那样,您可以提供 CustomJwtAuthenticationConverter 并提取角色。

        【讨论】:

          【解决方案4】:

          在您的安全配置中定义 jwt 身份验证转换器。您可以将您的声明名称设置为由授予权限的转换器使用。

          类似下面的东西,应该可以工作:

          
          import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
          import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
          
          
          @Bean
          public JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter() {
              // You can use setAuthoritiesClaimName method
              JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
              jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
              return jwtGrantedAuthoritiesConverter;
          
              // You can also add your custom converter here
          }
          
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              
              final JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
              jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(this.jwtGrantedAuthoritiesConverter());
              
              http
                  .sessionManagement()
                  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and()
                  .authorizeRequests()
                  .anyRequest()
                  .authenticated()
                  .and()
                  .oauth2ResourceServer()
                  .jwt()
                  .jwtAuthenticationConverter(jwtAuthenticationConverter);
          }
          
          

          【讨论】:

            猜你喜欢
            • 2017-11-13
            • 2023-03-12
            • 2018-05-17
            • 2020-05-25
            • 2018-07-25
            • 2019-04-05
            • 2018-08-29
            • 2022-01-07
            • 2021-08-18
            相关资源
            最近更新 更多