2015-07-10 103 views
0

我正在使用Spring-Security進行身份驗證/授權的Java應用程序,該應用程序連接到Spring-MVC服務器。登錄部分工作正常,並且我在Java應用程序中返回了JSESSIONID,但是當我向安全資源發出請求時,它失敗,Spring-Security無法找到任何已登錄的用戶。我在這裏做錯了什麼?Spring-Security:不確認在RestTemplate中設置的Cookie

安全的applicationContext.xml:

<security:http pattern="/resources/**" security="none"/> 

    <security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true"> 
     <security:form-login login-page="/login" login-processing-url="/j_spring_security_check" 
          default-target-url="/dashboard" always-use-default-target="false" 
          authentication-failure-url="/denied"/> 
     <security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService" 
           token-validity-seconds="1209600" data-source-ref="dataSource"/> 
     <security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/> 
     <!--<security:intercept-url pattern="/**" requires-channel="https"/>--> 
     <security:port-mappings> 
      <security:port-mapping http="8080" https="8443"/> 
     </security:port-mappings> 
     <security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/> 


     <security:session-management session-fixation-protection="migrateSession"> 
      <security:concurrency-control session-registry-ref="sessionRegistry" max-sessions="5" expired-url="/login"/> 
     </security:session-management> 

    </security:http> 

    <security:authentication-manager alias="authenticationManager"> 
     <security:authentication-provider ref="restaurantauthenticationprovider"/> 
     <security:authentication-provider ref="userauthenticationprovider"/> 
    </security:authentication-manager> 

    <beans:bean id="encoder" 
       class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
     <beans:constructor-arg name="strength" value="11"/> 
    </beans:bean> 

    <beans:bean id="restaurantauthenticationprovider" 
       class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> 
     <beans:property name="userDetailsService" ref="LoginServiceImpl"/> 
     <beans:property name="passwordEncoder" ref="encoder"/> 
    </beans:bean> 

    <beans:bean id="userauthenticationprovider" 
       class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> 
     <beans:property name="userDetailsService" ref="UserLoginServiceImpl"/> 
     <beans:property name="passwordEncoder" ref="encoder"/> 
    </beans:bean> 

正如我有2代表從登錄到檢查,我有2個DAOAuthenticationProviders。

UserLoginServiceImpl:

@Transactional 
@Service("loginuserDetailsService") 
public class UserLoginServiceImpl implements UserDetailsService { 


    @Autowired 
    private PersonDAO personDAO; 
    @Autowired 
    private UserAssembler userAssembler; 

    @Override 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException { 
     System.out.println("Username is "+username); 
     Person person = this.personDAO.findPersonByUserName(username.toLowerCase()); 
     if(person == null) { throw new UsernameNotFoundException("Wrong username or password");} 
     return userAssembler.buildUserFromUserEntity(person); 
    } 
} 

彙編:

@Service("userassembler") 
@Transactional 
public class UserAssembler { 

    @Transactional 
    User buildUserFromUserEntity(Person userEntity){ 
     System.out.println("We are in Userassembler"+userEntity.getEmail()); 
     String username = userEntity.getUsername().toLowerCase(); 
     String password = userEntity.getPassword(); 

     boolean enabled = userEntity.isEnabled(); 
     boolean accountNonExpired = userEntity.isAccountNonExpired(); 
     boolean credentialsNonExpired = userEntity.isCredentialsNonExpired(); 
     boolean accountNonLocked = userEntity.isAccountNonLocked(); 

     Collection<GrantedAuthority> authorities = new ArrayList<>(); 
     authorities.add(new SimpleGrantedAuthority("ROLE_USER")); 

     return new User(username,password,enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,authorities); 
    } 
} 

上面是配置,現在我要把這是失敗的其餘代碼:

Thread thread = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       Log.d("Username is ", username); 
       String jsessionid = rest.execute("http://192.168.178.60:8080/j_spring_security_check", HttpMethod.POST, 
         new RequestCallback() { 
          @Override 
          public void doWithRequest(ClientHttpRequest request) throws IOException { 
           request.getBody().write(("j_username=" + username + "&j_password=" + password).getBytes()); 
          } 
         }, new ResponseExtractor<String>() { 
          @Override 
          public String extractData(ClientHttpResponse response) throws IOException { 
           List<String> cookies = response.getHeaders().get("Cookie"); 
           if (cookies == null) { 
            cookies = response.getHeaders().get("Set-Cookie"); 
           } 
           String cookie = cookies.get(cookies.size() - 1); 
           System.out.println("Cookie is " + cookie); 
// The method below gets me which user is logged in, and I always get null for Controller method. 
           reply = rest.getForObject(
             "http://192.168.178.60:8080/dashboard", String.class); 

           int start = cookie.indexOf('='); 
           int end = cookie.indexOf(';'); 
           return cookie.substring(start + 1, end); 
          } 
         }); 

      } 
     }); 
     thread.start(); 

更新 最後,這個代碼ked:

//我從服務器獲取cookie,我爲每個請求手動設置cookie,cookie是一個靜態易失性字符串。

HttpHeaders requestHeaders = new HttpHeaders(); 
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid); 
HttpEntity requestEntity = new HttpEntity(null, requestHeaders); 

ResponseEntity rssResponse = rest.exchange(
            "http://192.168.178.60:8080/dashboard", 
            HttpMethod.GET, 
            requestEntity, 
            String.class); 

String abc = (String) rssResponse.getBody(); 
+0

你的人服務是什麼樣的?如果將方法更改爲: 字符串checkWichUserLoggedIn(Principal p){ return p == null? null:p.getName(); } –

+0

@RobWinch:我得到它爲空...因爲找不到用戶匿名用戶。我已經更新了我的主帖中的代碼,順便說一句,當我打印認證詳細信息時,會話Id爲空......我明白,RestTemplate在您進行身份驗證時在內部設置了Cookie,但似乎並不是這樣。 –

+0

你真的得到了JSESSIONID嗎?什麼是HTTP狀態碼?您使用的是哪種版本的Spring Security? –

回答

1

Spring的RestTemplate默認不會跟蹤cookie。這可以確保您不會意外地從一個用戶代表另一個用戶傳遞cookie(即JSESSIONID)(即,考慮在許多用戶利用相同RestTemplate的服務器上使用RestTemplate)。

如果要做到這一點,你可以使用這樣的配置是:

RestTemplate rest = new RestTemplate(); 

// initialize the RequestFactory to allow cookies 
HttpClient httpClient = HttpClientBuilder.create().build(); 
ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); 
rest.setRequestFactory(factory); 

MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>(); 
map.add("username", "user"); 
map.add("password", "password"); 

String result = rest.postForObject("http://localhost:8080/login", map, String.class); 

String hello = rest.postForObject("http://localhost:8080/", map, String.class); 

assertThat(hello).isEqualTo("Hello"); 

要使用此代碼,你需要確保你的HttpClient在classpath。例如,下面可能是在你的pom.xml如果你正在使用Maven:

<dependency> 
    <groupId>org.apache.httpcomponents</groupId> 
    <artifactId>httpclient</artifactId> 
    <version>4.5</version> 
</dependency> 

顯然,你需要確保你的HttpClient包含的版本,爲您的依賴工作。

+0

httpclient已被棄用,你是否有點更新?我發現http://stackoverflow.com/questions/29058727/i-need-an-option-to-httpclient-in-android-to-send-data-to-php-as-it-is-deprecate,但我找不到如何爲Rest設置數據。 –

+0

如果你在最新的httpclient(4.5),它不應該被棄用 –

+0

但httpclient有一個httpcore的要求,它不是4.5 ...另外,當我使用這些庫時,出現其他錯誤,所以我使用了android-httpclient。然後,我也遇到了一些問題,最後,我用了一些我在文章底部提到的內容。如果您知道如何優化它,請告訴我。 –