我设置了一个Keycloak服务器 . 配置领域和客户端等 . 我成功地编写了一个带有“org.keycloak:keycloak-spring-boot-starter”的Spring Boot服务并保护了我的RestController . 奇迹般有效 .
但是当我尝试使用Spring Security(没有keycloak特定的依赖项)时,我陷入困境 .
这是我的傻瓜:
dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.security.oauth:spring-security-oauth2')
compile('org.springframework.boot:spring-boot-starter-web')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
}
这是我的SecurityConfig:
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/person/**").hasRole("DEMO_SPRING_SECURITY")
.anyRequest().authenticated()
.and().formLogin().disable();
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("demo-client");
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setCheckTokenEndpointUrl(
"http://localhost:8280/auth/realms/demo-realm/protocol/openid-connect/token/introspect");
tokenServices.setClientId("demo-client");
tokenServices.setClientSecret("80e19056-7770-4a4a-a3c4-06d8ac8792ef");
resources.tokenServices(tokenServices);
}
}
现在我尝试访问服务器:
- 获取访问令牌(通过REST客户端)解码的JWT如下所示:
{
“jti”:“78c00562-d80a-4f5a-ab08-61ed10cb575c”,
“exp”:1509603570,
“nbf”:0,
“iat”:1509603270,
“iss”:“http:// localhost:8280 / auth / realms / demo-realm”,
“aud”:“演示客户”,
“sub”:“6ee90ba4-2854-49c1-9776-9aa95b6ae598”,
“典型”:“持票人”,
“azp”:“演示客户端”,
“auth_time”:0,
“session_state”:“68ce12fb-3b3f-429d-9390-0662f0503bbb”,
“acr”:“1”,
“client_session”:“ec0113e1-022a-482a-a26b-e5701e5edec1”,
“允许起源”:[],
“realm_access”:{
“角色”:[
“demo_user_role”
“uma_authorization”
]
},
“resource_access”:{
“帐户”:{
“角色”:[
“管理帐户”,
“管理帐户链接”,
“查看资料”
]
}
},
“名字”:“Jim Panse”,
“preferred_username”:“演示用户”,
“given_name”:“吉姆”,
“family_name”:“Panse”,
“email”:“user@dmoain.com”
}
但我得到一个AccessDeniedException .
2017-11-02 07:18:05.344 DEBUG 17637 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor:以前经过身份验证:
org.springframework.security.oauth2.provider.OAuth2Authentication@1f3ee7e1:校长:demo-client;证书:[保护];认证:真实;详细信息:remoteAddress = 127.0.0.1,tokenType = BearertokenValue =;未授予任何权限2017-11-02 07:18:05.348 DEBUG 17637 --- [nio-8080-exec-1] ossaccess.vote.AffirmativeBased:Voter:org.springframework.security.web.access.expression.WebExpressionVoter @ 14032696,返回:-1 2017-11-02 07:18:05.353 DEBUG 17637 --- [nio-8080-exec-1] osswaExceptionTranslationFilter:访问被拒绝(用户不是匿名的);委托给AccessDeniedHandler org.springframework.security.access.AccessDeniedException:访问被拒绝
我对RemoteTokenService进行了调试,发现Keycloak以完全相同的accessstoken响应 . 哪个好 . 但是 DefaultAccessTokenConverter
尝试从不存在的字段 authorities
读取用户角色 . 并且 OAuth2WebSecurityExpressionHandler
评估用户doenst具有任何角色 . - >访问被拒绝
所以我的问题:
什么是使Spring Security与Keycloak访问令牌一起工作的必要条件?
2 回答
通过keycloak管理控制台,您可以为客户端"demo-client"创建类型为 User Realm Role 的令牌映射器,其声明名称为"authorities" . 然后访问令牌包含此属性中的角色名称,并且不需要自定义DefaultAccessTokenConverter .
在我这里提出这个问题后,我自己找到了一个解决方案 . 有时尝试表达问题会有所帮助 .
解决方案是覆盖DefaultAccessTokenConverter以教他如何阅读“realm_access”字段 . 它丑陋但它有效: