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 从领域映射而不是资源映射中提取,我很好。
我已经设置了一个 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 从领域映射而不是资源映射中提取,我很好。