Auth0 注销在 Spring Boot 3 中不起作用

问题描述 投票:0回答:3

我正在使用 Spring Boot 2 遵循 auth0 的快速入门,但我的项目使用的是 Spring Boot 3,在更改已弃用的方法后,注销不再起作用。

安全配置:

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

@EnableWebSecurity
public class SecurityConfig {

    private final LogoutHandler logoutHandler;

    public SecurityConfig(LogoutHandler logoutHandler) {
        this.logoutHandler = logoutHandler;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .requestMatchers("/images/**").permitAll()
                .anyRequest().authenticated()
                .and().oauth2Login()
                .and().logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .addLogoutHandler(logoutHandler);
        return http.build();
    }

}

注销处理程序:

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;

@Controller
public class LogoutHandler extends SecurityContextLogoutHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());
    private final ClientRegistrationRepository clientRegistrationRepository;

    @Autowired
    public LogoutHandler(ClientRegistrationRepository clientRegistrationRepository) {
        this.clientRegistrationRepository = clientRegistrationRepository;
    }

    @Override
    public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                       Authentication authentication) {

        super.logout(httpServletRequest, httpServletResponse, authentication);
        String issuer = (String) getClientRegistration().getProviderDetails().getConfigurationMetadata().get("issuer");
        String clientId = getClientRegistration().getClientId();
        String returnTo = ServletUriComponentsBuilder.fromCurrentContextPath().build().toString();

        String logoutUrl = UriComponentsBuilder
                .fromHttpUrl(issuer + "v2/logout?client_id={clientId}&returnTo={returnTo}")
                .encode()
                .buildAndExpand(clientId, returnTo)
                .toUriString();

        log.info("Will attempt to redirect to logout URL: {}", logoutUrl);
        try {
            httpServletResponse.sendRedirect(logoutUrl);
        } catch (IOException ioe) {
            log.error("Error redirecting to logout URL", ioe);
        }
    }
    
    private ClientRegistration getClientRegistration() {
        return this.clientRegistrationRepository.findByRegistrationId("auth0");
    }
}

当我注销时,我不会被重定向,并且显示:You have been signed out 但我仍然可以访问受保护的资源,如果我转到 /profile 端点,我可以看到我的个人资料,就像我登录一样。当我使用 Spring Boot 2 运行 QuickStart 时,不会发生这种情况,一切正常,我的所有配置( client-secret、client-id、issuer-uri、回调和注销 url 配置正确,并且与 Spring Boot 3 应用程序相同,我仔细检查过)。任何帮助将不胜感激,我找不到 Spring Boot 3 和 Auth0 的教程。

spring spring-boot oauth-2.0 auth0 java-17
3个回答
0
投票

我能够使用 Spring Boot 3.0.4 来实现类似的应用程序。我正在使用最新的 okta-spring-boot 启动器,但我认为这并不重要。您可以尝试以下方法来处理注销吗?

@Configuration
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfiguration {

    @Value("${spring.security.oauth2.client.provider.auth0.issuer-uri}")
    private String issuer;
    @Value("${spring.security.oauth2.client.registration.auth0.client-id}")
    private String clientId;

    LogoutHandler oidcLogoutHandler() {
        return (request, response, authentication) -> {
            try {
                response.sendRedirect( issuer + "v2/logout?client_id=" + clientId + "&returnTo=http://localhost:8080/");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        };
    }

    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((requests) -> requests
                // allow anonymous access to the root page
                .requestMatchers("/").permitAll()
                // authenticate all other requests
                .anyRequest().authenticated());
        // configure logout handler
        http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).addLogoutHandler(oidcLogoutHandler());
        // enable OAuth2/OIDC
        http.oauth2Login();
        // enable Resource Server for API access
        http.oauth2ResourceServer().jwt();

        return http.build();
    }
}

0
投票

当会话在依赖方(RP 或 OAuth2 客户端)上失效时,要使 OIDC 提供者(OP 或 OAuth2 授权服务器)上的会话也失效,您应该使用 RP 发起的注销

Spring 有 注销成功处理程序

OidcClientInitiatedLogoutSuccessHandler
(反应式应用程序的等效处理程序记录在那里)。

问题是,Auth0 开箱即用,在两点上不遵循 OIDC 标准(但如果您联系支持人员,也许会遵循 OIDC 标准):

  • .well-known/openid-configuration 缺失
    end_session_endpoint
    。注销端点是
    {issuer-uri}v2/logout
    (在我的例子中:
    https://dev-ch4mpy.eu.auth0.com/v2/logout
    )。
  • 告诉注销后重定向到哪里的参数被命名为
    returnTo
    而不是
    post_logout_redirect_uri
    ,因为它应该是

因此,除了像上面链接的文档中那样进行配置之外,您还必须编写自己的

ServerLogoutSuccessHandler
。您可能会从其他答案中获得灵感来编写此处理程序,只需记住更改实现的接口(或扩展
SimpleUrlLogoutSuccessHandler
)。

我在spring-boot-starter-oauth2-client

周围写了薄薄的包装纸
。它公开了这样一个注销成功处理程序,您可以从属性中进行配置:

<dependency>
    <groupId>com.c4-soft.springaddons</groupId>
    <artifactId>spring-addons-webmvc-client</artifactId>
    <version>${project.version}</version>
</dependency>
@Configuration
@EnableMethodSecurity
public class WebSecurityConfig {
    // Yes, that's all, logout is configured in YAML 
    // with the rest of the security filter-chain
}
api-host: ${scheme}://localhost:${server.port}
ui-host: ${api-host}

scheme: http
auth0-issuer: https://dev-ch4mpy.eu.auth0.com/
autho-secret: change-me

server:
  port: 8080
  ssl:
    enabled: false
      
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
  security:
    oauth2:
      client:
        provider:
          auth0:
            issuer-uri: ${auth0-issuer}
        registration:
          auth0-confidential-user:
            authorization-grant-type: authorization_code
            client-name: Auth0
            client-id: TyY0H7xkRMRe6lDf9F8EiNqCo8PdhICy
            client-secret: ${autho-secret}
            provider: auth0
            scope: openid,profile,email,offline_access

com:
  c4-soft:
    springaddons:
      security:
        issuers:
        - location: ${auth0-issuer}
          username-claim: $['https://c4-soft.com/spring-addons']['name']
          authorities:
          - path: $.roles
          - path: $.permissions
        client:
          security-matchers:
          - /**
          permit-all:
          - /login/**
          - /oauth2/**
          - /
          - /ui/**
          - /swagger-ui.html
          - /swagger-ui/**
          client-uri: ${ui-host}
          post-login-redirect-path: /ui/greet
          post-logout-redirect-path: /ui/greet
          back-channel-logout-enabled: true
          oauth2-logout:
            - client-registration-id: auth0-confidential-user
              uri: ${auth0-issuer}v2/logout
              client-id-request-param: client_id
              post-logout-uri-request-param: returnTo
---
scheme: https

server:
  ssl:
    enabled: true

spring:
  config:
    activate:
      on-profile: ssl

0
投票

您可以使用 lambda 表达式:

.logout((logout)
    -> logout.logoutUrl("/api/v1/auth/logout")
    .addLogoutHandler(logoutHandler)
    .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext()))
  .build();
© www.soinside.com 2019 - 2024. All rights reserved.