spring security 登录成功跳转到 .well-known/appspecific/com.chrome.devtools.json
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・。)