gpt4 book ai didi

Keycloak + spring boot role authentification not working(Keyshaak+SpringBoot角色身份验证不起作用)

转载 作者:bug小助手 更新时间:2023-10-25 11:15:15 29 4
gpt4 key购买 nike



I'm developing a spring backend that uses a keycloak auth server. I'm struggeling to get role based authorization to work. I have created a user "dev_admin" in my realm and have given him the realm role "admin". I have the endpoint "debuf/admin" which is only accessible for users with the admin role. My security config looks like this:

我正在开发一个使用密钥罩身份验证服务器的Spring后端。我正在努力让基于角色的授权发挥作用。我已经在我的领域中创建了一个用户“dev_admin”,并为他分配了领域角色“admin”。我有一个端点“Debuf/admin”,只有具有admin角色的用户才能访问它。我的安全配置如下所示:


@Configuration
@EnableWebSecurity
public class SecurityConfig {

private final KeycloakLogoutHandler keycloakLogoutHandler;
SecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {
this.keycloakLogoutHandler = keycloakLogoutHandler;
}

@Bean
public SecurityFilterChain clientFilterChain(HttpSecurity http) throws Exception {
return http
.authorizeHttpRequests(auth -> {
auth
.requestMatchers(new AntPathRequestMatcher("/debug/public")).permitAll()
.requestMatchers(new AntPathRequestMatcher("/debug/authenticated")).authenticated()
.requestMatchers(new AntPathRequestMatcher("/debug/admin")).hasAnyRole("admin")
.anyRequest().authenticated();
})
.oauth2Login(Customizer.withDefaults())
.logout((conf) -> {
conf.addLogoutHandler(keycloakLogoutHandler);
conf.logoutSuccessUrl("/index");
})
.build();
}
}

However, after I log in as the dev_admin user and try to access the admin endpoint, i returns error 403. This is from the spring console:

但是,在我以dev_admin用户身份登录并尝试访问admin端点之后,我返回错误403。这是来自弹簧控制台的信息:


2023-09-10T19:44:54.653+02:00 TRACE 1400 --- [nio-8080-exec-7] estMatcherDelegatingAuthorizationManager : Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@5f29c29e]
2023-09-10T19:44:54.653+02:00 TRACE 1400 --- [nio-8080-exec-7] estMatcherDelegatingAuthorizationManager : Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@5f29c29e] using AuthorityAuthorizationManager[authorities=[ROLE_admin]]
2023-09-10T19:44:54.653+02:00 TRACE 1400 --- [nio-8080-exec-7] w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [Authentication=OAuth2AuthenticationToken [Principal=Name: [dev_admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=1blJDsXc37Pz3uyqygg43A, sub=413591c7-3213-40a4-be2d-82dc69fe1264, email_verified=true, iss=http://localhost:8081/realms/users, typ=ID, preferred_username=dev_admin, given_name=dev, nonce=f_D-DARLucc5Y0Uau8QLhgv2srTM0gK3MDA1zpaDXDM, sid=fab4e120-b249-4e76-bffb-c5a4820fa536, aud=[core-server], acr=1, azp=core-server, auth_time=2023-09-10T17:44:50Z, name=dev admin, exp=2023-09-10T17:49:50Z, session_state=fab4e120-b249-4e76-bffb-c5a4820fa536, family_name=admin, iat=2023-09-10T17:44:50Z, [email protected], jti=a7e9ff04-2526-4ff8-82c1-1216ee6d673a}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=95CD2FEF619B032D2A30C89CFAD0740C], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]]] from SPRING_SECURITY_CONTEXT
2023-09-10T19:44:54.653+02:00 TRACE 1400 --- [nio-8080-exec-7] o.s.s.w.a.AnonymousAuthenticationFilter : Did not set SecurityContextHolder since already authenticated OAuth2AuthenticationToken [Principal=Name: [dev_admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=1blJDsXc37Pz3uyqygg43A, sub=413591c7-3213-40a4-be2d-82dc69fe1264, email_verified=true, iss=http://localhost:8081/realms/users, typ=ID, preferred_username=dev_admin, given_name=dev, nonce=f_D-DARLucc5Y0Uau8QLhgv2srTM0gK3MDA1zpaDXDM, sid=fab4e120-b249-4e76-bffb-c5a4820fa536, aud=[core-server], acr=1, azp=core-server, auth_time=2023-09-10T17:44:50Z, name=dev admin, exp=2023-09-10T17:49:50Z, session_state=fab4e120-b249-4e76-bffb-c5a4820fa536, family_name=admin, iat=2023-09-10T17:44:50Z, [email protected], jti=a7e9ff04-2526-4ff8-82c1-1216ee6d673a}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=95CD2FEF619B032D2A30C89CFAD0740C], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]]
2023-09-10T19:44:54.653+02:00 TRACE 1400 --- [nio-8080-exec-7] o.s.s.w.a.ExceptionTranslationFilter : Sending OAuth2AuthenticationToken [Principal=Name: [dev_admin], Granted Authorities: [[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]], User Attributes: [{at_hash=1blJDsXc37Pz3uyqygg43A, sub=413591c7-3213-40a4-be2d-82dc69fe1264, email_verified=true, iss=http://localhost:8081/realms/users, typ=ID, preferred_username=dev_admin, given_name=dev, nonce=f_D-DARLucc5Y0Uau8QLhgv2srTM0gK3MDA1zpaDXDM, sid=fab4e120-b249-4e76-bffb-c5a4820fa536, aud=[core-server], acr=1, azp=core-server, auth_time=2023-09-10T17:44:50Z, name=dev admin, exp=2023-09-10T17:49:50Z, session_state=fab4e120-b249-4e76-bffb-c5a4820fa536, family_name=admin, iat=2023-09-10T17:44:50Z, [email protected], jti=a7e9ff04-2526-4ff8-82c1-1216ee6d673a}], Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=95CD2FEF619B032D2A30C89CFAD0740C], Granted Authorities=[OIDC_USER, SCOPE_email, SCOPE_openid, SCOPE_profile]] to access denied handler since access is denied

I also checked the dev_admin JWT token by using the "impersonate" feature and the role is contaiend in the token. I also noticed that in my browser the token that was saved as a cookie is much shorter and does not contain the role. These are all the clues I have found but I still don't know why its not working. If someone knows, whats going on that would be very helpful.

我还使用“impersonate”特性检查了dev_admin JWT令牌,并且该角色包含在令牌中。我还注意到,在我的浏览器中,保存为cookie的令牌要短得多,并且不包含角色。这些都是我找到的线索,但我仍然不知道为什么它不工作。如果有人知道,这将是非常有帮助的。


EDIT: I'm not using keycloak adapters by the way. it just looks like that because of the "keycloaklogouthandler" which sends a request to keycloaks logout endpoint

编辑:顺便说一句,我没有使用钥匙斗篷适配器。它看起来就像这样,因为“keyloaklogouthandler”将请求发送到密钥伪装注销端点


I should also mention that the client and resource server are the same server in my case. I think the problem has something to do with the security configuration. Here is my application.yml:

我还应该提到,在我的例子中,客户端和资源服务器是同一服务器。我认为这个问题与安全配置有关。以下是我的申请表.yml:


  security:
oauth2:
resourceserver.jwt:
issuer-uri: ${keycloak.baseUrl}/realms/${keycloak.userRealm}
jwk-set-uri: ${keycloak.baseUrl}/auth/realms/${keycloak.userRealm}/protocol/openid-connect/certs

client:
registration.keycloak:
client-id: myclient
authorization-grant-type: authorization_code
scope: openid

admin_user: ???
admin_password: ???

provider.keycloak:
issuer-uri: ${keycloak.baseUrl}/realms/${keycloak.userRealm}
user-name-attribute: preferred_username

更多回答
优秀答案推荐

According to the manual for an OAuth2 client with oauth2Login, you should provide with a GrantedAuthoritiesMapper bean or override the OAuth2UserService (in the case of a resource server with JWT decoder, you would provide a Converter<Jwt, ? extends AbstractAuthenticationToken>, maybe a manually configured JwtAuthenticationConverter).

根据具有oAuth2Login的OAuth2客户端的手册,您应该提供GrantedAuthoritiesMapper Bean或覆盖OAuth2UserService(在使用JWT解码器的资源服务器的情况下,您将提供Converter ,可能是手动配置的JwtAuthenticationConverter)。


Do not use Keycloak adapters for Spring. It was deprecated long ago and does not work with Spring Security 6 / Boot 3.

不要将Keyloak适配器用于Spring。它很久以前就被弃用了,不能与Spring Security6/Boot3一起使用。


Do not fetch user roles from Keycloak. This is way too inefficient. Instead, read it from tokens. As you are writing an OAuth2 client (which reads the ID token, not the access token), you might have to activate the mappers: Client scopes -> roles -> Mappers -> realm roles and enable Add to ID token as well as Add to userinfo (you might do the same with client roles if you use it).

请勿从Keyloak获取用户角色。这太低效了。取而代之的是,从代币上阅读它。在编写OAuth2客户端(它读取ID令牌,而不是访问令牌)时,您可能必须激活映射器:客户端范围->角色->映射器->领域角色,并启用Add to ID Token和Add to UserInfo(如果您使用客户端角色,可以对其执行相同的操作)。


This other answer contains sample conversion from Keycloak roles to Spring authorities in both resource servers and clients.

另一个答案包含了从Keycloak角色到资源服务器和客户端中的Spring权限的示例转换。



It seems there might be an issue with the way you're specifying the role in your SecurityConfig. To use role-based authorization with Keycloak, you need to specify the role using the Keycloak-specific role prefix. By default, Keycloak uses the ROLE_ prefix for roles.

您在SecurityConfig中指定角色的方式可能有问题。要将基于角色的授权与Keyloak一起使用,您需要使用特定于Keyloak的角色前缀指定角色。默认情况下,Keyloak对角色使用ROLE_前缀。


Here's how you can modify your SecurityConfig to use the correct role prefix:

以下是如何修改您的SecurityConfig以使用正确的角色前缀:


@Configuration
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}

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

@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/debug/public").permitAll()
.antMatchers("/debug/authenticated").authenticated()
.antMatchers("/debug/admin").hasRole("admin") // Use "hasRole" with the role name without "ROLE_" prefix
.anyRequest().authenticated()
.and()
.oauth2Login()
.defaultSuccessURL("/success")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/index");
}
}

In this modified configuration:

在此修改后的配置中:


We extend KeycloakWebSecurityConfigurerAdapter to take advantage of Keycloak-specific features.

我们扩展了KeyloakWebSecurityConfigurerAdapter以利用特定于Keyloak的功能。


We configure the AuthenticationManagerBuilder to use the keycloakAuthenticationProvider provided by Keycloak.

我们将AuthenticationManagerBuilder配置为使用由Keyloak提供的keyloakAuthenticationProvider。


Make sure that your Keycloak realm configuration matches this setup, especially regarding the role name. The role in Keycloak should be named "admin" without the ROLE_ prefix.

确保您的密钥罩领域配置与此设置匹配,特别是在角色名称方面。Keyloak中的角色应该命名为“admin”,不带Role_前缀。


Hope I was helpful.

希望我能帮上忙。


Additionally, ensure that the Keycloak client configuration for your Spring Boot application includes the correct roles mapping.

此外,确保您的Spring Boot应用程序的Keyloak客户端配置包括正确的角色映射。


After these modifications, try accessing the /debug/admin endpoint again. If the role is correctly assigned in Keycloak and your Keycloak client configuration is accurate, role-based authorization should work as expected.

在这些修改之后,再次尝试访问/DEBUG/ADMIN终结点。如果在Keyloak中正确分配了角色,并且您的Keyloak客户端配置正确,则基于角色的授权应该会按预期工作。


更多回答

I have done some more debugging and the problem seems to be that the JWT spring checks for authorities is the ID token which doesnt actually contain any roles. I should also mention that my resource server and client are the same, the spring securty config is the one in my post. I think I didnt configure it properly. I'm editing the post to provide more info

我已经做了更多的调试,问题似乎是JWT对权限的Spring检查是ID令牌,它实际上并不包含任何角色。我还应该提到,我的资源服务器和客户端是相同的,Spring安全配置就是我在帖子中提到的那个。我想我没有正确配置它。我正在编辑这篇帖子,以提供更多信息

Read my answer again, you'll find the recipe to add roles to ID tokens. You are using oauth2Login => requests are authorized with session cookie, not Bearer access token. In the other answer, follow the link the OAuth2 essentials section of my tutorials.

再读一遍我的答案,你会发现向ID令牌添加角色的秘诀。您正在使用oauth2Login=>使用会话Cookie授权请求,而不是使用承载访问令牌。在另一个答案中,按照我的教程的OAuth2 Essentials部分的链接进行操作。

Alright, I overrode the OAuth2UserService like in the manual and extracted the "realm_access" claim from the jwt token and mapped it to the user. I'm now able to secure my endpoints with roles. Thanks

好的,我覆盖了手册中的OAuth2UserService,并从JWT令牌中提取了“Realm_Access”声明,并将其映射到用户。我现在能够使用角色保护我的终端。谢谢

Glad I could help. Things usually get easier when you read the manual (and the entirety of an answer) ;)

很高兴能帮上忙。当你阅读手册(以及完整的答案)时,事情通常会变得更容易;)

I'm a little bit worried about something though. I have now added a resource server filter chain which uses springs resource server support and set the JwtGrantedAuthoritiesConverter. However, when I place a break point in the converter it never stops there. I'm worried it might not even validate my tokens properly. Any idea on how to test/debug this? Updated config here: hastebin.com/share/paridiviyo.java

不过,我还是有点担心一些事情。现在,我已经添加了一个使用Springs资源服务器支持的资源服务器筛选器链,并设置了JwtGrantedAuthoritiesConverter。然而,当我在转换器中放置一个断点时,它永远不会停止。我担心它甚至可能无法正确验证我的令牌。对如何测试/调试这一点有什么想法吗?此处更新了配置:hastebin.com/share/pariDiviyo.java

Unfortunately that doesn't really help since I'm not using a keycloak adapter (apparently its deprecated). I use keycloaks REST API instead. Thank you for the answer though

不幸的是,这并没有真正起到什么作用,因为我没有使用键盘斗篷适配器(显然它已被弃用)。我使用的是Keycoaks REST API。不过,还是要谢谢你的回答

I can see, so You need to implement logic (possibly in a custom service) to fetch the user's roles from Keycloak after authentication using the Keycloak REST API. You will need to make a request to Keycloak's /auth/admin/realms/{realm}/users/{userId}/roles endpoint to obtain the user's roles. Implement custom logic to compare the user's roles obtained from Keycloak with the required roles for each endpoint. You can use this logic to grant or deny access.

我可以看到,所以你需要实现逻辑(可能在一个自定义服务中),以便在使用Keycloak REST API进行身份验证后从Keycloak获取用户的角色。您需要向Keycloak的/auth/admin/realms/{realm}/users/{userId}/roles端点发出请求以获取用户的角色。实现自定义逻辑,将从Keycloak获得的用户角色与每个端点所需的角色进行比较。您可以使用此逻辑来授予或拒绝访问。

Hm if all else fails I suppose that is an option.

嗯,如果所有其他方法都失败了,我想这是一个选择。

No, definitely not an option to consider. Keycloak adapters where deprecated almost two years ago and calling Keycloak API each time you need to access user roles is very inefficient. Instead, configure Keycloak to add roles to tokens and Spring Security to turn Keycloak roles into Spring authorities.

不,绝对不是一个可以考虑的选项。几乎两年前就不推荐使用的Keyloak适配器,每次需要访问用户角色时都会调用Keyloak API,效率非常低。相反,配置Keyloak以向令牌添加角色,并配置Spring Security以将Keyloak角色转换为Spring权限。

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com