我有一个使用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>
}
改变此组件状态的登录功能是一个简单的REST调用(使用superagent),它使用附带的基本身份验证凭据获取用户信息:
login: function(username, password){
return {
then: function(callback){
request
.get(rootUrl + 'me')
.auth(username, password)
.end((err, res) => {
callback(res);
});
}
}
}
在后端方面,我在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
标头)的异常处理。因此,尽管覆盖了BasicAuthenticationEntryPoint
,浏览器仍会向我显示弹出窗口。
更奇怪的是,当我在浏览器弹出窗口中提供正确的详细信息时,它仍然会返回401状态。
这似乎是一个基本设置:一个简单的REST服务,带有Spring Security和前端的单页应用程序。有没有人有类似的问题?
答案 0 :(得分:1)
您是否已尝试注册拒绝访问权限的处理程序?
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,以查看过滤器链中某处是否有异常处理完毕,应该是。
答案 1 :(得分:1)
如果您不想弹出浏览器,最好避免使用401
。
对于AJAX,我建议改为使用403
作为身份验证入口点。
response.sendError(HttpServletResponse.SC_FORBIDDEN)
如果您需要在“真实”禁止(当用户经过身份验证但不允许访问)及以上之间进行辩护,您可以在响应正文或自定义标题中传递信息。