2015-10-13 27 views
2

我有一個單頁的應用程序與Facebook的開發陣營框架,在這裏我使用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); 
      }); 
     } 
    } 
} 

在後端側,我有一個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狀態。

雖然這看起來像一個基本的設置:Spring Security的簡單REST服務和前端的單頁應用程序。有沒有人有類似的問題?

+0

嘗試創建一個單獨的登錄頁面,實現起來要容易得多:它將包含您的組件,並且應該打開,即permitAll()。應用程序頁面應該是「認證()」。通過這種方法,您的this.state.sessionState =='LOGGEDIN'邏輯變得多餘。 –

+0

我之前正在使用這種方法,但我覺得這使得代碼更乾淨,因爲我不需要實現一種機制來跟蹤用戶試圖訪問的URL。如果用戶想要轉到https:// domain/task/id並需要先登錄,則採用這種方法會自動運行:首先顯示登錄屏幕,然後顯示目標頁面。我的問題僅限於身份驗證請求。 –

+0

好吧,也許我不清楚你的目標,但我寧願把注意力集中在保持目標網址的問題上,春季安全讓你做到這一點。參見[this](http://stackoverflow.com/questions/14573654/spring-security-redirect-to-previous-page-after-succesful-login)。順便說一句,在客戶端保持授權邏輯給你一種'假'授權,因爲你可以通過瀏覽器中的js調試器來驗證你自己。乾杯! –

回答

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當你不覺得在安全上下文的主體(控制器內部的代碼),看看是否某處過濾器鏈中的異常處理,它應該是。

+0

我還沒有試過這個,今晚會這麼做。目前,我只有exceptionHandling()。authenticationEntryPoint() –

1

如果您不希望瀏覽器彈出,請最好避免401

對於AJAX,我建議使用403代替驗證入口點。

response.sendError(HttpServletResponse.SC_FORBIDDEN) 

如果需要在反應體或作爲自定義首部的「真實」禁止(當用戶被認證,但不允許訪問)和以上,就可以將信息傳遞之間distingish。

相關問題