Spring security for REST api在验证失败时显示浏览器弹出窗口

Spring security for REST api在验证失败时显示浏览器弹出窗口,spring,rest,spring-security,reactjs,spring-boot,Spring,Rest,Spring Security,Reactjs,Spring Boot,我有一个使用Facebook的React框架开发的单页应用程序,我使用这一点JSX来确定用户是否登录: render: function() { return <div> <BrandBar/> <div className="container"> <TopBar/> {this.state.sessionState == 'LOADING' ? (<h1>Loading

我有一个使用Facebook的React框架开发的单页应用程序,我使用这一点JSX来确定用户是否登录:

render: function() {
    return <div>
      <BrandBar/>
      <div className="container">
        <TopBar/>
        {this.state.sessionState == 'LOADING' ? (<h1>Loading</h1>) : (this.state.sessionState == 'LOGGEDIN' ? this.props.children : <Login/>)}
      </div>
    </div>
}
在后端,我在Spring Boot中有一个REST api:

控制器:

@RequestMapping(value = "/me",
        produces = {APPLICATION_JSON},
        method = RequestMethod.GET)
public User getMe() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (principal != null && principal instanceof CurrentUser){
        return ((CurrentUser) principal).getUser();
    }

    return null;
}

@RequestMapping("/stop")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void stop(HttpSession session) {
    session.invalidate();
}
安全配置:

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
                .httpBasic().and()
                .authorizeRequests().anyRequest().authenticated()
                .and().anonymous().disable()
                .exceptionHandling().authenticationEntryPoint(new BasicAuthenticationEntryPoint(){
            @Override
            public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
            }
        });

    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

}
只要我提供的信息正确,登录就可以正常工作,但当我提供错误凭据时,服务器会绕过返回普通401的异常处理(没有
WWW-Authenticate
头)。因此,尽管覆盖了
基本身份验证入口点
,浏览器仍会显示弹出窗口

更奇怪的是,当我在浏览器弹出窗口中提供正确的详细信息时,它仍然返回401状态


这看起来像是一个基本的设置:一个简单的REST服务,带有SpringSecurity,前端有一个单页应用程序。有人遇到过类似问题吗?

您是否已尝试注册拒绝访问处理程序

http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl());

public class AccessDeniedHandlerImpl implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse     response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendError(HttpStatus.UNAUTHORIZED.value());
    }
}

就像测试一样当您在安全上下文(控制器内的代码)中找不到主体时,尝试抛出AuthenticationException,以查看是否在筛选器链中的某个位置处理了异常。如果您不希望浏览器弹出,最好避免使用
401

对于AJAX,我建议使用
403
作为身份验证入口点

response.sendError(HttpServletResponse.SC_禁止)

如果您需要区分“真实”禁止(当用户经过身份验证但不允许访问时)和更高级别,您可以在响应正文中传递信息或作为自定义标题传递信息。

尝试创建单独的登录页面,它更容易实现:它将包含您的组件,并且应该是打开的,即permitAll()。应用程序页面应为“authenticated()”。使用这种方法,您的this.state.sessionState=='LOGGEDIN'逻辑变得多余。我之前使用过这种方法,但我觉得这有助于代码更简洁,因为我不需要实现跟踪用户试图访问哪个url的机制。如果用户想进入并需要首先登录,使用这种方法它会自动工作:首先显示登录屏幕,然后显示目标页面。我的问题仅仅是身份验证请求。好吧,也许我不清楚您的目标,但我更愿意专注于保留目标url的问题,spring security允许您这样做。看见顺便说一下,在客户端保留auth逻辑会给您一种“假”授权,因为您可以通过浏览器中的js调试器对自己进行身份验证。干杯你用的是什么版本的Spring Security/Spring Boot?我还没试过这个,今晚我会试的。目前,我只有exceptionHandling().authenticationEntryPoint()
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl());

public class AccessDeniedHandlerImpl implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse     response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        response.sendError(HttpStatus.UNAUTHORIZED.value());
    }
}