Configure Keycloak 21 with Spring Security 6

huangapple go评论69阅读模式
英文:

Configure Keycloak 21 with Spring Security 6

问题

I'm here to provide the translated content for you. Here's the translation of your provided text:

我正在尝试设置Spring Security与Keycloak 21一起工作,但不幸的是,互联网上的大多数教程都已过时。我已经配置了Keycloak中的客户端和领域,但Spring Security不清楚应该如何配置。我尝试了来自这个链接的代码:

我添加了以下Gradle依赖项:

implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-security:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.1.0'

以及以下YAML配置:

spring:
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: https://ip/realms/admin_console_realm
        registration:
          keycloak-login:
            authorization-grant-type: authorization_code
            client-name: My Keycloak instance
            client-id: admin_console_client
            client-secret: qwerty
            provider: keycloak
            scope: openid,profile,email,offline_access
      resourceserver:
        jwt:
          issuer-uri: https://ip/realms/admin_console_realm
          jwk-set-uri: https://ip/realms/admin_console_realm/protocol/openid-connect/certs

不清楚我需要在这里添加什么Spring Security配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.authorizeHttpRequests()
                .requestMatchers("/*").hasAuthority("ROLE_TECH_SUPPORT")
                .anyRequest().authenticated()
                .and()
                .oauth2Login();

        return  httpSecurity.build();
    }
}

我已经将角色添加到Keycloak客户端:

Configure Keycloak 21 with Spring Security 6

当我在浏览器中打开一个Rest API链接时,我被重定向到Keycloak的登录页面。成功验证后,我收到以下消息:

无法访问ip,您没有查看此页面的授权。
HTTP错误403

您知道如何解决这个问题吗?

英文:

I'm trying to setup Spring Security to work with Keycloak 21 but unfortunately most of the tutorials on Internet are outdated. I configured client and realms into Keycloak but Spring security is not clear what should be. I tried the code from this link:

I added these gradle dependencies:

implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-security:3.1.0'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.1.0'

and this yml config:

spring:
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: https://ip/realms/admin_console_realm
        registration:
          keycloak-login:
            authorization-grant-type: authorization_code
            client-name: My Keycloak instance
            client-id: admin_console_client
            client-secret: qwerty
            provider: keycloak
            scope: openid,profile,email,offline_access
      resourceserver:
        jwt:
          issuer-uri: https://ip/realms/admin_console_realm
          jwk-set-uri: https://ip/realms/admin_console_realm/protocol/openid-connect/certs

It's not clear what I need to add as a Spring security configuration here:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

        httpSecurity.authorizeHttpRequests()
                .requestMatchers("/*").hasAuthority("ROLE_TECH_SUPPORT")
                .anyRequest().authenticated()
                .and()
                .oauth2Login();

        return  httpSecurity.build();
    }
}

I added the role into Keycloak client:

Configure Keycloak 21 with Spring Security 6

When I open a Rest API link into the browser I'm redirected to Keycloak's login page. After successful authentication I get:

Access to ip was deniedYou don't have authorization to view this page.
HTTP ERROR 403

Do you know how I can fix this issue?

答案1

得分: 3

Here is the translated content:

如果您正在尝试公开受Keycloak服务器(身份验证服务器)保护的REST API,则您的应用程序是OAuth2资源服务器,而不是OAuth2客户端服务器,除非它们是公共的,否则您不能使用浏览器访问您的REST API。

对于具有REST API的资源服务器,您可以使用以下代码:

  1. application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://<KEYCLOAK_SERVER_IP>/realms/<YOUR_REALM_NAME>
          jwk-set-uri: http://<KEYCLOAK_SERVER_IP>/realms/<YOUR_REALM_NAME>/protocol/openid-connect/certs
  1. 从Keycloak服务器获取JWT令牌(此CURL等同于用于从Keycloak获取访问令牌的Postman请求,您可以在此处找到更多信息 https://documenter.getpostman.com/view/7294517/SzmfZHnd
curl --location 'http://<KEYCLOAK_SERVER_IP>/realms/test/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=<YOUR_USER_NAME>' \
--data-urlencode 'password=<YOUR_USER_PASSWORD>' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=<KEYCLOAK_CLIENT_ID>' \
--data-urlencode 'client_secret=<KEYCLOAK_CLIENT_SECRET>' \
--data-urlencode 'scope=openid';
  1. 使用 https://jwt.io/ 检查您的访问令牌
...
"realm_access": {
    "roles": [
      "default-roles-test",
      "offline_access",
      "MY_REALM_ROLE",
      "uma_authorization"
    ]
  },
  "resource_access": {
    "test-client": {
      "roles": [
        "MY_CLIENT_ROLE"
      ]
    },
...

现在,我们需要告诉Spring Security从JWT令牌中查找角色信息的位置。

  1. WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .authorizeHttpRequests(registry -> registry
                        .requestMatchers("/my-api/**").hasRole("MY_REALM_ROLE")
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2Configurer -> oauth2Configurer.jwt(jwtConfigurer -> jwtConfigurer.jwtAuthenticationConverter(jwt -> {
                    Map<String, Collection<String>> realmAccess = jwt.getClaim("realm_access");
                    Collection<String> roles = realmAccess.get("roles");
                    var grantedAuthorities = roles.stream()
                            .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
                            .collect(Collectors.toList());
                    return new JwtAuthenticationToken(jwt, grantedAuthorities);
                })))
        ;

        return httpSecurity.build();
    }
}

确保您在Keycloak中为用户进行适当的角色映射。

现在,要使用您的REST API,您可以使用Postman。在Postman中添加Bearer Token授权,并使用从Keycloak服务器生成的最新访问令牌。

英文:

if you are trying to expose rest APIs secured with Keycloak Server (Authentication Server) then your application is a OAuth2 resource server not a OAuth2 client server and also you can't use browser for accessing your rest APIs unless they are public.
For Resource Server with rest APIs you can use the below code

  1. application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://&lt;KEYCLOAK_SERVER_IP&gt;/realms/&lt;YOUR_REALM_NAME&gt;
          jwk-set-uri: http://&lt;KEYCLOAK_SERVER_IP&gt;/realms/&lt;YOUR_REALM_NAME&gt;/protocol/openid-connect/certs
  1. Get JWT TOKEN from Keycloak Server (this curl is equivalent to postman request for keycloak to get access token, you can find more here https://documenter.getpostman.com/view/7294517/SzmfZHnd)
curl --location &#39;http://&lt;KEYCLOAK_SERVER_IP&gt;/realms/test/protocol/openid-connect/token&#39; \
--header &#39;Content-Type: application/x-www-form-urlencoded&#39; \
--data-urlencode &#39;username=&lt;YOUR_USER_NAME&gt;&#39; \
--data-urlencode &#39;password=&lt;YOUR_USER_PASSWORD&gt;&#39; \
--data-urlencode &#39;grant_type=password&#39; \
--data-urlencode &#39;client_id=&lt;KEYCLOAK_CLIENT_ID&gt;&#39; \
--data-urlencode &#39;client_secret=&lt;KEYCLOAK_CLIENT_SECRET&gt;&#39; \
--data-urlencode &#39;scope=openid&#39;
  1. Inspect your access token using https://jwt.io/
...
&quot;realm_access&quot;: {
    &quot;roles&quot;: [
      &quot;default-roles-test&quot;,
      &quot;offline_access&quot;,
      &quot;MY_REALM_ROLE&quot;,
      &quot;uma_authorization&quot;
    ]
  },
  &quot;resource_access&quot;: {
    &quot;test-client&quot;: {
      &quot;roles&quot;: [
        &quot;MY_CLIENT_ROLE&quot;
      ]
    },
...

Now, we need to tell spring security from where it has look for Roles information in the JWT token.

  1. WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {

// Note: Please change &#39;/mp-api/**&#39; to your desired rest controller path.
        httpSecurity
                .authorizeHttpRequests(registry -&gt; registry
                        .requestMatchers(&quot;/my-api/**&quot;).hasRole(&quot;MY_REALM_ROLE&quot;)
                        .anyRequest().authenticated()
                )
                .oauth2ResourceServer(oauth2Configurer -&gt; oauth2Configurer.jwt(jwtConfigurer -&gt; jwtConfigurer.jwtAuthenticationConverter(jwt -&gt; {
                    Map&lt;String, Collection&lt;String&gt;&gt; realmAccess = jwt.getClaim(&quot;realm_access&quot;);
                    Collection&lt;String&gt; roles = realmAccess.get(&quot;roles&quot;);
                    var grantedAuthorities = roles.stream()
                            .map(role -&gt; new SimpleGrantedAuthority(&quot;ROLE_&quot; + role))
                            .collect(Collectors.toList());
                    return new JwtAuthenticationToken(jwt, grantedAuthorities);
                })))
        ;

        return httpSecurity.build();
    }
}

Make sure you have proper Role Mappings for User in Keycloak.

Now, for using your rest API you can use Postman. In Postman add
Bearer Token Authorization and use the latest generated access token from keycloak server.

答案2

得分: 2

我们最近将应用程序迁移到使用Spring Boot 3.0.4和Keycloak 21.0.1。配置如下:

实施 'org.springframework.boot:spring-boot-starter-oauth2-client:3.0.4'
实施 'org.springframework.boot:spring-boot-starter-security:3.0.4'
实施 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.0.4'

YAML配置:

<!-- 语言:yml -->
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://<keycloak-base-url>/realms/<realms-name>
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://<keycloak-base-url>/realms/<realms-name>/protocol/openid-connect/certs

Spring安全配置:

<!-- 语言:java -->

@Configuration
public class WebSecurityConfig {
	
	@Autowired
    private CorsConfigurationSource corsConfigurationSource;
	
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
		httpSecurity
            .headers()
                .frameOptions().disable();
        httpSecurity
            .authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2ResourceServer().jwt();
        httpSecurity
            .cors()
               .configurationSource(corsConfigurationSource)
               .and()
            .csrf().disable();
        return httpSecurity.build();
	}
}
英文:

We recently migrated our application to use Spring Boot 3.0.4 and Keycloak 21.0.1 The configuration look like below,

implementation &#39;org.springframework.boot:spring-boot-starter-oauth2-client:3.0.4&#39;
implementation &#39;org.springframework.boot:spring-boot-starter-security:3.0.4&#39;
implementation &#39;org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.0.4&#39;

YAML config:

<!-- language: yml -->
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://<keycloak-base-url>/realms/<realms-name>
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://<keycloak-base-url>/realms/<realms-name>/protocol/openid-connect/certs

Spring Security configuration is:

<!-- language: java -->

@Configuration
public class WebSecurityConfig {
	
	@Autowired
    private CorsConfigurationSource corsConfigurationSource;
	
    @Bean
	public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
		httpSecurity
            .headers()
                .frameOptions().disable();
        httpSecurity
            .authorizeHttpRequests()
                .anyRequest().authenticated()
                .and()
            .oauth2ResourceServer().jwt();
        httpSecurity
            .cors()
               .configurationSource(corsConfigurationSource)
               .and()
            .csrf().disable();
        return httpSecurity.build();
	}
}

答案3

得分: 1

以下是您提供的代码部分的中文翻译:

// 如果有人来到这里查找在Spring Security版本6.1和Spring Boot 3.1中与Keycloak配合使用的实现是什么样的。
// 如果您遇到关于JwtDecoder的错误,请关注这一行代码:.jwkSetUri(jwkSetUri)

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity(debug = true)
public class WebSecurityConfig {

    public static final String ADMIN = "admin";
    public static final String USER = "user";

    @Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}")
    private String jwkSetUri;

    private final JwtAuthConverter jwtAuthConverter;

    @Bean
    public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorizeHttpRequests) ->
                        authorizeHttpRequests
                                .requestMatchers("/api/duenos/**").hasAnyRole(ADMIN, USER)
                                .requestMatchers("/api/objetos_extraviados/**").hasAnyRole(ADMIN, USER)
                                .anyRequest().authenticated()
                )
                .oauth2ResourceServer((oauth2ResourceServer) ->
                        oauth2ResourceServer
                                .jwt((jwt) ->
                                        jwt
                                                .jwtAuthenticationConverter(jwtAuthConverter)
                                                .jwkSetUri(jwkSetUri)
                                )
                )
                .sessionManagement((sessionManagement) -> sessionManagement
                                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                );
        return http.build();
    }
}

请注意,代码中的HTML实体编码(如")已被保留,以确保代码的正确性。

英文:

In case someone comes here looking for what an implementation in version 6.1 of Spring Security, Spring Boot 3.1 configured to work with keycloack would look like.

If you get an error about JwtDecoder, this line takes care of it: .jwkSetUri(jwkSetUri)

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity(debug = true)
public class WebSecurityConfig {

    public static final String ADMIN = &quot;admin&quot;;
    public static final String USER = &quot;user&quot;;


    @Value(&quot;${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}&quot;)
    private String jwkSetUri;

    private final JwtAuthConverter jwtAuthConverter;


    @Bean
    public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorizeHttpRequests) -&gt;
                        authorizeHttpRequests
                                .requestMatchers(&quot;/api/duenos/**&quot;).hasAnyRole(ADMIN, USER)
                                .requestMatchers(&quot;/api/objetos_extraviados/**&quot;).hasAnyRole(ADMIN, USER)
                                .anyRequest().authenticated()
                )
                .oauth2ResourceServer((oauth2ResourceServer) -&gt;
                        oauth2ResourceServer
                                .jwt((jwt) -&gt;
                                        jwt
                                                .jwtAuthenticationConverter(jwtAuthConverter)
                                                .jwkSetUri(jwkSetUri)
                                )
                )
                .sessionManagement((sessionManagement) -&gt; sessionManagement
                                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                );
        return http.build();
    }

}

Las dependencias que usé:
spring-boot-starter-oauth2-resource-server
spring-security-oauth2-jose
spring-boot-starter-security

huangapple
  • 本文由 发表于 2023年5月22日 23:33:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76307796.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定