Spring 使用 Keycloak 的安全 OAuth2 - 访问用户信息

Spring Security OAuth2 with Keycloak - Accessing User Information

我有一个 Spring Security OAuth2Keycloak 设置。

Client 应用程序端,工件如下所示:

application.yml

server.port: 8182

spring:
    security:
        oauth2:
            client:
                registration:
                    keycloak:
                        client-id: myclient-ac
                        client-secret: 81e3fd9f-52ce-4549-8ea9-ae53e754da89
                        authorization-grant-type: authorization_code
                        redirect-uri: http://localhost:8182/login/oauth2/code/myclient-ac
                        scope: openid
                provider:
                    keycloak:
                        issuer-uri: http://localhost:8180/auth/realms/myrealm
                        #authorization-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/auth
                        #token-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/token
                        #user-info-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/userinfo
                        #jwk-set-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/certs
                        #user-name-attribute: preferred_username

SecurityConfig.java

@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests().anyRequest().permitAll()
            .and()
            .oauth2Login().disable()
            .oauth2Client();
            
        return http.build();
    }
}

WebClientConfig.java

@Configuration
public class WebClientConfig {
    @Bean
    WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = 
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        
        return WebClient.builder()
            .apply(oauth2Client.oauth2Configuration())
            .build();
    }    

    @Bean
    public OAuth2AuthorizedClientManager authorizedClientManager(
        ClientRegistrationRepository clientRegistrationRepository,
        OAuth2AuthorizedClientRepository authorizedClientRepository) {

        OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
            .authorizationCode()
            .refreshToken()
            .build();

        DefaultOAuth2AuthorizedClientManager authorizedClientManager = 
            new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
        
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }
}

MyRestControllerClient.java

@RestController
public class MyRestControllerClient {
    private static final Logger LOGGER = LoggerFactory.getLogger(MyRestControllerClient.class);
    
    @Autowired
    private WebClient webClient;     
    
    @GetMapping("/helloworld")
    public String helloworld(@RegisteredOAuth2AuthorizedClient("keycloak") OAuth2AuthorizedClient authorizedClient) {
        String body = webClient
            .get()
            .uri("http://localhost:8181/helloworld")
            .attributes(oauth2AuthorizedClient(authorizedClient))
            .retrieve()
            .bodyToMono(String.class)
            .block();
        
        LOGGER.info(body);
        
        return body;
    } 
    
    @GetMapping("/oidc-principal")
    public OidcUser getOidcUserPrincipal(@AuthenticationPrincipal OidcUser principal) {
        return principal;
    }    
}

访问 http://localhost:8182/helloworld 会导致被重定向到位于 Keycloak 的登录页面。提供 usernamepassword,我可以成功访问我的 /helloworld 端点。

我还想访问用户信息,根据 4.1. Accessing User Informationhttps://www.baeldung.com/spring-security-openid-connect 可以通过

REST 控制器中完成
@GetMapping("/oidc-principal")
public OidcUser getOidcUserPrincipal(@AuthenticationPrincipal OidcUser principal) {
    return principal;
}

将此端点添加到我的 REST 控制器,并在 /helloworld 端点之后访问它,导致 principal 成为 null

如何获取用户信息?

我改了这个

@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests().anyRequest().permitAll()
            .and()
            .oauth2Login().disable()
            .oauth2Client();
            
        return http.build();
    }
}

.oauth2Login()
.and()
.oauth2Client();

现在 principal 充满了信息。

但是现在有什么区别呢? OAuth2 按预期与 .oauth2Login().disable() 一起工作,行为是相同的,我被重定向到 Keycloak 的登录页面,无论是否使用 .disable()

都会发生登录