Spring Boot 和 Keycloak - GrantedAuthority 返回时总是空的

Spring Boot and Keycloak - GrantedAuthority always coming back empty

我已经设置了一个 REST API 我正在尝试使用 Keycloak 进行保护,并且 运行 本地 Docker 中的所有内容都在组合中。 REST API 在 host/service rest-api 上是 运行,Keycloak 在 auth-service 上是 运行,两者前面都有一个代理容器(所以以 /auth 开头的任何内容都会转到 Keycloak,其他任何内容都会转到 API).

安全配置 - 我已经尝试了一些东西,但目前它是:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfiguration
        extends KeycloakWebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests()
                .anyRequest()
                .permitAll();
        http.csrf().disable();
        http.cors();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source =
                new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration(
                "/**",
                new CorsConfiguration().applyPermitDefaultValues()
        );
        return source;
    }

    /**
     * Global configuration.
     *
     * @param auth Authentication Manager Builder
     * @throws Exception If security can't be configured
     */
    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth)
            throws Exception {
        SimpleAuthorityMapper grantedAuthorityMapper =
                new SimpleAuthorityMapper();
        grantedAuthorityMapper.setPrefix("ROLE_");

        KeycloakAuthenticationProvider keycloakAuthenticationProvider =
                keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
                grantedAuthorityMapper
        );
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(
                new SessionRegistryImpl()
        );
    }
}

然后是一个简单的控制器:

@RestController
@CrossOrigin("*")
@RequestMapping("/api/v3/auth")
public class AuthController {
    /**
     * Logger.
     */
    private static final Logger LOGGER =
            LoggerFactory.getLogger(AuthController.class);

    /**
     * Default constructor.
     */
    AuthController() {
        LOGGER.info("AuthController Constructor.");
    }
...
    /**
     * Checks/initiates a user login.
     *
     * @return Information about the current user's auth status
     */
    @RolesAllowed("ROLE_user")
    @GetMapping(
            value = "/login1",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    @ResponseBody
    public Map<String, String> login1() {
        final Map<String, String> response = new HashMap<String, String>();
        response.put("status", "OK");

        final Authentication authentication =
                SecurityContextHolder.getContext().getAuthentication();
        final List<String> roles = new ArrayList<String>();
        for (GrantedAuthority authority : authentication.getAuthorities()) {
            roles.add(authority.getAuthority());
        }
        response.put(
                "Current user roles",
                "[" + String.join(",", roles) + "]"
        );

        return response;
    }
}

@RolesAllowed 注释确实启动了 Keycloak 集成。我被带到登录页面,我被允许登录,我被传回 /sso/login 的 REST 应用程序,并且该响应设置了我期望的 JWT:

Set-Cookie: KEYCLOAK_ADAPTER_STATE=eyJhbGciOi...

使用https://jwt.io/进行调试,那个令牌对我来说看起来不错,具体来说:

  "realm_access": {
    "roles": [
      "offline_access",
      "uma_authorization",
      "user"
    ]
  },

但是,当我返回登录页面时,我收到了 403 禁止。所以我在同一个控制器中编写了第二种方法:

    @GetMapping(
            value = "",
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    @ResponseBody
    public Map<String, String> read() {
        final Map<String, String> response = new HashMap<String, String>();
        response.put("status", "OK");

        final Authentication authentication =
                SecurityContextHolder.getContext().getAuthentication();

        response.put(
                "AUTHENTICATION NAME",
                authentication.getName()
        );
        response.put(
                "AUTHENTICATION PRINCIPAL",
                authentication.getPrincipal().toString()
        );
        response.put(
                "AUTHENTICATION AUTHORITIES",
                authentication.getAuthorities().toString()
        );

        int i = 0;
        for (GrantedAuthority authority : authentication.getAuthorities()) {
            response.put(
                    "AUTHORITY-" + i++,
                    authority.getAuthority()
            );
        }

        return response;
    }

输出如下:

{
  "AUTHENTICATION PRINCIPAL": "<GUID I expect>",
  "AUTHENTICATION NAME": "<GUID I expect>",
  "status": "OK",
  "AUTHENTICATION AUTHORITIES": "[]"
}

所以...我显然从 Keycloak 获得了身份验证 JWT,看起来 Spring 正试图用它做正确的事情。但是 GrantedAuthority 列表总是空的,所以我总是收到 403。

对这里的问题有什么建议吗?

当然,归结为一个配置行:

keycloak.use-resource-role-mappings = true

将其更改为 false 从领域映射而不是资源映射中提取,我很好。