带有 Keycloak 的 Spring Security OAuth2 - 访问用户信息

Posted

技术标签:

【中文标题】带有 Keycloak 的 Spring Security OAuth2 - 访问用户信息【英文标题】:Spring Security OAuth2 with Keycloak - Accessing User Information 【发布时间】:2021-11-10 07:45:43 【问题描述】:

我有一个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

如何获取用户信息?

【问题讨论】:

您的具体问题是什么?由于您已经回答了自己的帖子并编辑了 OP,所以我不清楚。 我认为我的答案是我的问题的解决方案。我仍然不明白 .oauth2Login().disable() 和 .oauth2Login() 的区别,因为整体行为是相同的。 .oauth2Login() 添加了对 OpenID Connect 1.0 作为身份验证机制的支持。没有它,您实际上并没有在您的应用程序中进行身份验证,这就是为什么@AuthenticatedPrincipal 不会返回有关当前登录用户的正确信息的原因。您可以单独使用.oauth2Client(),并使用其他东西登录您的应用程序,或者您可以一起使用它们并同时使用keycloak(登录)登录您的应用程序,并使用返回的访问令牌对资源服务器进行安全API调用您的架构(客户端)。 This section of the reference docs 会详细解释。 【参考方案1】:

我改变了这个

@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() 的情况下

【讨论】:

以上是关于带有 Keycloak 的 Spring Security OAuth2 - 访问用户信息的主要内容,如果未能解决你的问题,请参考以下文章

带有 Keycloak 的 Spring 应用程序返回 401 错误

带有 Spring Boot KeycloakSecurityContext 的 Keycloak 始终为空

带有 keycloak 设置的 Spring Security (HttpSecurity)

带有 keycloak 的 Spring Cloud 微服务

带有 Keycloak 的 Spring Security OAuth2 - 访问用户信息

在 Spring Boot 和 Spring Security 中,不活动、过期的令牌会导致带有 Keycloak 的 IllegalStateException