springsecurity的AuthenticationSuccessHandler响应问题

我用springsecurity做登录认证,然后希望自定义登录成功后的处理,所以就实现了AuthenticationSuccessHandler接口,打算回写一个ok。

@Component
public class SuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        httpServletResponse.addHeader("Access-Control-Allow-Origin","*");
        httpServletResponse.getWriter().write("ok");
    }
}

但情况是这个ok直接被当成url,然后跳转了。

img

然后响应是这样子的

img

然后我用api测试工具呢又发现这个ok其实是在body里的

img


这是为什么呢?

该回答引用于gpt与OKX安生共同编写:
  • 该回答引用于gpt与OKX安生共同编写:

您好,根据您提供的信息,可能是因为您没有在您的Spring Security配置中将自定义的SuccessHandler注册为默认的成功处理程序。可以使用以下代码片段在您的WebSecurityConfigurerAdapter中进行配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private SuccessHandler successHandler;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
        .authorizeRequests()
          // your authorization config here
          .and()
        .formLogin()
          .successHandler(successHandler)
          .permitAll()
          // your login page URL here
          .loginPage("/login")
          .and()
        .logout()
          // your logout URL here
          .logoutUrl("/logout")
          .permitAll();
  }
}

请注意,这个示例假设您的登录页面位于"/login",登出URL为"/logout"。

如果您已经正确地注册了SuccessHandler,并且仍然遇到问题,请检查您是否正确地设置了请求头和响应正文。可以尝试在浏览器控制台或调试器中检查HTTP响应以获取更多信息。

  • 另外可能是你的控制器没有设置响应的content-type导致浏览器无法识别回传的是json类型数据,从而出现了将 "ok" 当成 url 的问题。可以在控制器类上添加注解 @RestController 或者在处理方法上添加注解 @ResponseBody 来指定响应的内容类型。例如:



@RestController

public class UserController {

  

    @PostMapping("/login")

    //@ResponseBody

    public String login() {

        System.out.println("login success");

        return "ok";

    }

}

注解 @ResponseBody 可以让处理方法返回纯文本,而不是视图名。如果你不想在处理方法上添加这个注解,可以将其放到控制器类上面,这样在这个控制器的所有处理方法中都可以使用。

如果还有问题,可以给我更多的上下文或者详细的代码片段,我可以帮你再看一下。

  • 您好,根据您提供的代码,我看到您使用了Spring Security来处理登录认证,并且设置了成功处理器(successHandler)。而且您也已经在响应头中添加了跨域请求的相关信息,但是在浏览器中无法加载响应内容。

首先,如果您使用了Chrome浏览器,可以按下F12键打开开发者工具,然后点击Network选项卡,查看是否有错误提示或者响应内容。如果确实有响应内容,但是无法加载,可能是因为浏览器的安全策略导致的跨域问题。您可以尝试在Spring Security配置中添加以下代码解决跨域问题:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors().and() // 添加cors配置
        .csrf().disable()
        // ...其他配置
}

如果您还需要在登录成功后返回JSON格式数据给客户端,可以在successHandler的实现类中添加@ResponseBody注解来将返回值转换为JSON格式。例如:

@Component
public class MySuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
    @Override
    @ResponseBody // 添加该注解
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws ServletException, IOException {
        // 设置返回格式为JSON
        response.setContentType("application/json;charset=UTF-8");
        // 创建输出流
        PrintWriter out = response.getWriter();
        // 构造返回数据
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", 200);
        resultMap.put("message", "登录成功");
        // 将返回数据转换为JSON格式并输出到响应中
        out.write(new ObjectMapper().writeValueAsString(resultMap));
        out.flush();
        out.close();
    }
}

  • 另外根据您提供的信息,我还可以看出您在配置Spring Security时使用了自定义的SuccessHandler来处理登录成功后的逻辑。根据您的情况,您需要将成功处理程序的响应内容写入响应体中,而不是在浏览器的地址栏中显示。

最好的解决方案是在SuccessHandler实现中将响应内容写入响应体中。举个例子:



@Component
public class MySuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        // 获得用户信息
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        // 设置响应头
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write("{\"code\":0,\"message\":\"登录成功\",\"data\":{\"username\":\"" + userDetails.getUsername() + "\"}}");
        // 关闭响应输出流
        response.getWriter().close();
    }
}

在上面的代码中,我们将响应的内容设置为JSON格式,然后将其写入响应体中,以此来告知浏览器登录成功的信息。

  • 另外,关于无法加载响应内容的问题,您可以尝试清除浏览器缓存,或者使用浏览器的开发者工具查看请求和响应的详细信息,以便更好地了解问题出在哪里。如果您发现这是一个跨域问题,则可以通过添加@CrossOrigin注释或在Spring Security中配置允许跨域的选项来解决它。
  • 望采纳哦~