首页 » java

spring security 登录成功跳转到 .well-known/appspecific/com.chrome.devtools.json

   发表于:java评论 (0)   热度:7

Spring Security 登录成功后,页面没有跳转到你预期的地址,反而跳转到了 .well-known/appspecific/com.chrome.devtools.json

 

这个路径并非 Spring Security 本身的配置导致,核心原因通常是:Chrome 开发者工具的干扰.well-known/appspecific/com.chrome.devtools.json 是 Chrome 浏览器开发者工具在调试过程中自动发起的请求路径,登录成功后 Spring Security 会默认跳转到登录前的最后一个请求路径,如果登录前浏览器(尤其是开着开发者工具时)自动请求过这个路径,就会被 Spring Security 记录为 redirectUrl

 

解决方案 1: 如果是erp等后台管理类的软件的话直接  用 defaultSuccessUrl("/index", true)   强制跳转到一个页面最简单高效

核心思路是覆盖 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;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            // 关闭 csrf(测试环境可选,生产环境不建议)
            .csrf(csrf -> csrf.disable())
            // 配置授权规则
            .authorizeHttpRequests(auth -> auth
                // 放行静态资源和公共路径
                .requestMatchers("/login", "/css/**", "/js/**").permitAll()
                // 其他请求需要认证
                .anyRequest().authenticated()
            )
            // 配置表单登录
            .formLogin(form -> form
                .loginPage("/login") // 自定义登录页地址
                .usernameParameter("username") // 用户名参数名
                .passwordParameter("password") // 密码参数名
                // 方案1:简单配置 - 强制跳转到首页(优先级最高)
                .defaultSuccessUrl("/index", true) 
                // 方案2:自定义成功处理器(更灵活,可根据用户角色跳转)
                // .successHandler(authenticationSuccessHandler())
            )
            // 配置退出登录
            .logout(logout -> logout
                .logoutSuccessUrl("/login?logout") // 退出成功跳转地址
                .permitAll()
            );

        return http.build();
    }

    // 方案2:自定义登录成功处理器(可选,比 defaultSuccessUrl 更灵活)
    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        SimpleUrlAuthenticationSuccessHandler handler = new SimpleUrlAuthenticationSuccessHandler();
        // 强制跳转到指定地址,忽略 SavedRequest
        handler.setDefaultTargetUrl("/index");
        // 禁用「使用之前保存的请求跳转」的功能(核心解决你的问题)
        handler.setAlwaysUseDefaultTargetUrl(true);
        return handler;
    }

    // 注:如果需要配置用户认证(如内存用户),可添加以下 Bean
    /*
    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }
    */
}
  • defaultSuccessUrl("/index", true)

    • 第一个参数:登录成功后默认跳转的地址(如 /index 首页)。
    • 第二个参数 true强制使用这个地址跳转,忽略登录前的 SavedRequest(核心解决你的问题)。如果设为 false,则只有在没有 SavedRequest 时才跳转到该地址。
  • 自定义 AuthenticationSuccessHandler

    • setAlwaysUseDefaultTargetUrl(true):禁用 Spring Security 保存的「之前请求路径」,始终跳转到 setDefaultTargetUrl 指定的地址。
    • 适合需要根据用户角色 / 权限动态跳转的场景(比如管理员跳 /admin,普通用户跳 /user)。
  • 额外建议

    • 测试时可以关闭 Chrome 开发者工具的「Network」面板的自动请求(或直接关闭开发者工具),避免浏览器自动发起的无效请求被记录。
    • 放行 .well-known 路径(可选,防止该路径被拦截):.requestMatchers("/.well-known/**").permitAll()

如果是erp等后台管理类的软件的话直接  用 defaultSuccessUrl("/index", true)   强制跳转到一个页面最直接简单高效

 

解决方案2:   过滤 / 忽略无效的 SavedRequest(最直接)

让 Spring Security 不记录 .well-known、静态资源、无效接口等路径的 SavedRequest,从源头避免这些路径被作为跳转目标。通过自定义 RequestCache 实现,只保留合法的业务路径,

适用场景:不想完全禁用 SavedRequest(比如希望跳转到用户登录前访问的合法业务页面),但需要过滤掉无效路径。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;

@Configuration
public class SecurityRequestCacheConfig {

    // 定义需要忽略的无效路径前缀
    private static final List<String> IGNORED_PATHS = Arrays.asList(
        "/.well-known/", // 屏蔽 Chrome 调试工具路径
        "/css/", "/js/", "/img/", // 屏蔽静态资源
        "/favicon.ico", // 屏蔽浏览器图标请求
        "/error" // 屏蔽错误页面请求
    );

    @Bean
    public RequestCache requestCache() {
        return new HttpSessionRequestCache() {
            @Override
            public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
                // 仅当请求路径不是无效路径时,才保存为 SavedRequest
                String requestUri = request.getRequestURI();
                boolean isInvalidPath = IGNORED_PATHS.stream().anyMatch(requestUri::startsWith);
                if (!isInvalidPath) {
                    super.saveRequest(request, response);
                }
                // 无效路径不保存,自然不会被作为跳转目标
            }

            @Override
            public SavedRequest getRequest(HttpServletRequest request, HttpServletResponse response) {
                // 可选:获取时也过滤,双重保障
                SavedRequest savedRequest = super.getRequest(request, response);
                if (savedRequest != null) {
                    String redirectUrl = savedRequest.getRedirectUrl();
                    boolean isInvalid = IGNORED_PATHS.stream().anyMatch(redirectUrl::contains);
                    if (isInvalid) {
                        return null; // 无效路径返回 null,使用默认跳转
                    }
                }
                return savedRequest;
            }
        };
    }

    // 将自定义 RequestCache 注入 SecurityFilterChain
    // 需在 SecurityConfig 中添加:
    /*
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .requestCache(requestCache -> requestCache.requestCache(requestCache())) // 注入自定义缓存
            // 其他配置...
        ;
        return http.build();
    }
    */
}

方案3:配置授权规则,放行无效路径且不记录认证

.well-known、静态资源等无效路径,不仅放行访问,还通过 anonymous() 标记为「无需认证」,Spring Security 不会为这类请求记录 SavedRequest

anonymous()permitAll() 更严格 ——permitAll() 允许所有用户(包括匿名和已认证)访问,而 anonymous() 仅允许匿名用户访问,且不会为这类请求触发认证流程,自然不会记录 SavedRequest

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            // 放行无效路径,并标记为 anonymous(不触发认证,不记录 SavedRequest)
            .requestMatchers("/.well-known/**", "/css/**", "/js/**", "/favicon.ico").anonymous()
            // 登录页放行
            .requestMatchers("/login").permitAll()
            // 其他请求需要认证
            .anyRequest().authenticated()
        )
        .formLogin(form -> form
            .loginPage("/login")
            // 保留默认逻辑:有合法 SavedRequest 则跳转,无则跳默认页
            .defaultSuccessUrl("/dashboard", false) 
        );
    return http.build();
}

 

(。・v・。)
喜欢这篇文章吗?欢迎分享到你的微博、QQ群,并关注我们的微博,谢谢支持。