2017-04-16 151 views
0

我正在開發一個使用Spring Boot的Spring REST應用程序。我正在使用角JS客戶端來使用Spring REST API。Spring CORE Spring CORS安全認證問題

我使用的堆棧:

Spring Boot 1.4.2 , Spring Security , Angular JS , Tomcat 8 

我的問題是:

1)登錄時,用戶被成功地認證。自定義認證成功處理程序返回200個狀態碼

2)認證成功之後,當克林特發送另一個請求訪問procted資源,HttpSession的是NULL

3)由於其中當SecurityContextPersistenceFilter嘗試檢索SecurityContextHttpSession它返回爲空和 和再次服務器發送請求/login資源

4)所以,我的問題是:

1)爲什麼httpsesion是空的第二個請求?

2)我觀察到,春季安全返回JSESSIONID作爲第一succesfull認證後的cookie。

3)但是,在此之後,客戶端不在請求因此第二請求發送該JSESSIONID不會在同一個會話。

4)如果是這樣的話,怎麼SecurityContext將如果SESSION檢索是不成立的?

請幫助,因爲我不能夠在這裏

編輯1着手:

我正在使用彈簧安全提供存儲用戶默認設置。我的安全配置是波紋管:

@Configuration 
@EnableWebSecurity 
@ComponentScan({"com.atul.security"}) 
public class SecurityConfig extends WebSecurityConfigurerAdapter{ 

    @Autowired 
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler; 


    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
      http 
      .formLogin().successHandler(authenticationSuccessHandler) 
      .and() 
      .csrf().disable() 
      .authorizeRequests() 
      .antMatchers(HttpMethod.OPTIONS,"/*").permitAll() 
      .antMatchers("/index.html", "/home.html", "/login.html", "/").permitAll() 
      .anyRequest().authenticated() 
      .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); 
    } 

} 

我得到以下用戶爲認證用戶:

org.sprin[email protected]9055c2bc: 
Principal: anonymousUser; Credentials: [PROTECTED]; 
Authenticated: true; 
Details: org.sprin[email protected]b364: 
RemoteIpAddress: 0:0:0:0:0:0:0:1; 
SessionId: null; 
Granted Authorities: ROLE_ANONYMOUS 

請求但現在失敗的:AbstractSecurityInterceptorAccessDecisionVoter返回了authenticated表達和拒絕訪問異常錯誤被拋出

+0

您是否禁用了csrf令牌安全性? –

+0

是的,我在配置spring安全性時做了這個 – Atul

+1

@Atul:你知道這個意思嗎?和()。sessionManagement()。sessionCreationPolicy(SessionCreationPolicy.STATELESS); –

回答

1

由於RESTFUL服務不保持狀態,因此沒有休息會話,讀取此堆棧溢出帖子:

Do sessions really violate RESTfulness?

如果你想知道如何正確地構建基於Spring Security的服務REST檢查本教程:

http://www.baeldung.com/securing-a-restful-web-service-with-spring-security

希望這有助於。

您正在使用formLogin安全,這意味着您需要添加某種數據存儲以對用戶進行身份驗證。

這裏是在內存中的數據存儲從春天文檔的例子:根據這個例子

@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Bean 
    public UserDetailsService userDetailsService() throws Exception { 
     InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); 
    manager.createUser(User.withUsername("user").password("password").roles("USER").build()); 
    manager.createUser(User.withUsername("admin").password("password").roles("USER","ADMIN").build()); 
    return manager; 
} 

} 

,你想用密碼的用戶名和密碼

您是成功進行身份驗證試圖應用angularJS作爲您的前端技術的安全性,有一個偉大的教程如何實現這一點,我已經在我的項目上實現它,這裏是鏈接:

https://spring.io/guides/tutorials/spring-security-and-angular-js/

對於初學者,您需要使用httpBasic而不是formLogin作爲安全身份驗證方法。

+0

我嘗試過使用sessionCreationPolicy(SessionCreationPolicy.STATELESS)。請求現在將通過UsernamePasswordAuthenticationFilter。問題是:.anyRequest()。authenticated()現在返回false並引發Access拒絕異常。 – Atul

+0

您是否有任何數據源(內存或數據庫)來對用戶進行身份驗證? –

+0

我使用Spring Security提供的默認用戶 - Spring Boot。 – Atul

0

經過長時間的撞擊之後,我終於找到了解決辦法。

步驟如下: 1)基於表單的登錄需要建立會話。當驗證成功時,服務器會發送Set-Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08; Path=/springbootrest; HttpOnly標題作爲迴應。

2)瀏覽器必須在每次請求發送這個頭否則不會有任何會話建立和認證失敗

3),但因爲我是用CORS(我的服務器和用戶界面的應用程序駐留在本地不同的端口系統),瀏覽器在請求未通過身份驗證時未發送Cookie:JSESSIONID=3974317C6DE34865B6726FCFD4C98C08

4)我必須在我的角度js客戶端添加下面的行$httpProvider.defaults.withCredentials = true;後,該瀏覽器開始發送請求上面的標題。

5)在服務器端,我必須在CORSFilter中添加以下代碼。

response.setHeader("Access-Control-Allow-Credentials","true"); 
     response.setHeader("Access-Control-Allow-Origin", "http://localhost:8186"); 
     response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); 
     response.setHeader("Access-Control-Max-Age", "3600"); 
     response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type, Version"); 
     response.setHeader("Access-Control-Expose-Headers", "X-Requested-With, WWW-Authenticate, Authorization, Origin, Content-Type"); 

     final HttpServletRequest request = (HttpServletRequest) req; 
     if("OPTIONS".equalsIgnoreCase(request.getMethod())) { 
      response.setStatus(HttpServletResponse.SC_OK); 
     } else { 
      chain.doFilter(req, res); 
     }