尽管断开连接,我仍然可以访问资源,而无需再次向我的提供商进行身份验证

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

我的应用程序注销不起作用。 当我点击注销按钮时,如果确认注销,我会保持相同的连接->我不需要再次登录即可访问资源,我可以直接访问资源页面。 注销确认窗口不会出现,如果我写 /logout:

但我总是可以再次访问资源而无需登录。 在浏览器控制台中,我有这个:

客户的安全配置:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)

public class SecurityConfig  {
   
    private final ClientRegistrationRepository clientRegistrationRepository;
   
    public  SecurityConfig(ClientRegistrationRepository clientRegistrationRepository){
        this.clientRegistrationRepository=clientRegistrationRepository;
    }

    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf(Customizer.withDefaults())//config par def.
                .authorizeHttpRequests(ar-> ar.anyRequest().authenticated())
                .headers(h->h.frameOptions(fo->fo.disable()))
                .csrf(crsf->crsf.ignoringRequestMatchers("/h2-console/**"))
                .authorizeHttpRequests(ar->ar.requestMatchers("/","/webjars/**","/h2-console/**",  "/oauth2Login/**").permitAll())
                .oauth2Login(al->al.loginPage("/oauth2Login").defaultSuccessUrl("/"))
                .logout((logout)->logout
                        .logoutSuccessHandler(oidcLogoutSuccessHandler())
                        .logoutSuccessUrl("/").permitAll()
                        .clearAuthentication(true)
                        .deleteCookies("JSESSIONID"))
                        .exceptionHandling(eh->eh.accessDeniedPage("/notAuthorized"));
        return http.build();

    }

    private OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() {
        final OidcClientInitiatedLogoutSuccessHandler oidcClientInitiatedLogoutSuccessHandler=
                new OidcClientInitiatedLogoutSuccessHandler(this.clientRegistrationRepository);
        oidcClientInitiatedLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}?logoutsuccess=true");
        return oidcClientInitiatedLogoutSuccessHandler;
    }
    @Bean
    public GrantedAuthoritiesMapper userAuthoritiesMapper() {
        return (authorities -> {
            final Set<GrantedAuthority> mappedAuthorities=new HashSet<>();
            authorities.forEach((authority)->{
                if (authority instanceof OidcUserAuthority oidcAuth){
                    mappedAuthorities.addAll(mappedAuthorities(oidcAuth.getIdToken().getClaims()));
                    System.out.println(oidcAuth.getAttributes());
                } else if (authority instanceof OAuth2UserAuthority oauth2Auth) {
                    mappedAuthorities.addAll(mappedAuthorities(oauth2Auth.getAttributes()));
                }
            });
        return mappedAuthorities;

    });
    }

    private List<SimpleGrantedAuthority> mappedAuthorities(final Map<String, Object> attributes) {
        final Map<String, Object> realmAccess= (Map<String, Object>) attributes.getOrDefault("realm_access", Collections.emptyMap());
        final Collection<String> roles=((Collection<String>)realmAccess.getOrDefault("roles", Collections.emptyList()));
        return roles.stream()
                .map(SimpleGrantedAuthority::new)
                .toList();
    }

控制器:

@Controller   
    public class CustomerController {
        /**
         * acces a interface
         */
        private  CustomerRepository customerRepository;
        private ClientRegistrationRepository clientRegistrationRepository;
        public CustomerController(CustomerRepository customerRepository, ClientRegistrationRepository registrationRepository) {
            this.customerRepository = customerRepository;
            this.clientRegistrationRepository = clientRegistrationRepository;
        }


        @GetMapping("/customers")
        @PreAuthorize("hasAuthority('ADMIN')")
        public String customers(Model model){  
            List<Customer> customersList = customerRepository.findAll();
            model.addAttribute("customers", customersList);
            return "customers";//return attributeName du model=CustomerList
        }

        @GetMapping("/products")
        
        public String products(Model model){
            SecurityContext context= SecurityContextHolder.getContext();
            Authentication authentication = context.getAuthentication();
            OAuth2AuthenticationToken oAuth2AuthenticationToken = (OAuth2AuthenticationToken) authentication;
            DefaultOidcUser oidcUser= (DefaultOidcUser) oAuth2AuthenticationToken.getPrincipal();
            String jwtTokenValue=oidcUser.getIdToken().getTokenValue();
            RestClient restClient= RestClient.create("http://localhost:8085");
            List<Product> products=restClient.get()
                    .uri("/products")
                    .headers(httpHeaders ->httpHeaders.set(HttpHeaders.AUTHORIZATION,"Bearer"+"jwtTokenValue"))
                    .retrieve()
                    .body(new ParameterizedTypeReference<>() {});
            model.addAttribute("products", products);
            return "products";
        }


        
        @GetMapping("/auth")
        @ResponseBody
        public Authentication auth(Authentication authentication){
            return authentication;
        }
      
        @GetMapping("/")
        public String index(){
            return "index";
        }

        @GetMapping("/notAuthorized")
        public String notAuthorized(){
            return "notAuthorized";
        }

        @GetMapping("/oauth2Login")
        public String oauth2Login(Model model){
            String authorizationRequestBaseUri="oauth2/authorization";
            Map<String, String> oauth2AuthenticationUrls=new HashMap();
            Iterable<ClientRegistration> clientRegistrations=(Iterable<ClientRegistration>)clientRegistrationRepository;
            clientRegistrations.forEach(clientRegistration->{
                oauth2AuthenticationUrls.put(clientRegistration.getClientName(),
                        authorizationRequestBaseUri+"/"+ clientRegistration.getRegistrationId());
            });
            model.addAttribute("urls",oauth2AuthenticationUrls);
            return "oauth2Login";
        }

感谢您的帮助。

spring keycloak logout
1个回答
0
投票

/logout
的请求应该是
POST
(这意味着CSRF保护将出现在游戏中),并且当您配置OIDC注销成功处理程序时,重定向应该是到授权服务器。这里您被重定向到登录,因为注销被拒绝(错误的 HTTP 动词)。

一旦修复了 HTTP 谓词(发送

POST
请求而不是
GET
),您可能会面临 CSRF 问题,因为您正在使用 SPA 并且没有为此类应用程序配置 CSRF 保护...

© www.soinside.com 2019 - 2024. All rights reserved.