2

我使用彈簧引導和彈簧安全。restTemplatebuider訪問問題

在我的休息控制器,我有一個方法

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
@EnableWebSecurity 
public class ApplicationSecurity extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private RESTAuthenticationEntryPoint authenticationEntryPoint; 

    @Autowired 
    private RESTAuthenticationFailureHandler authenticationFailureHandler; 

    @Autowired 
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler; 

    @Autowired 
    private UserDetailsService userDetailsService; 

    @Bean 
    public PasswordEncoder encoder() { 
     return new BCryptPasswordEncoder(); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService).passwordEncoder(encoder()); 
    } 

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

     http.authorizeRequests() 
       .antMatchers("/login").permitAll() 
       .antMatchers("/rest/**").authenticated(); 

     http.csrf().disable(); 
     http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); 

     http.formLogin().successHandler(authenticationSuccessHandler); 
     http.formLogin().failureHandler(authenticationFailureHandler); 
     http.logout().logoutUrl("/logout"); 
     http.logout().logoutSuccessUrl("/"); 

     // CSRF tokens handling 
     //http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class); 
    } 

} 

@RequestMapping(value = "/rest") 
@RestController 
public class MemberController { 

    @GetMapping(value = "/members/card") 
    public boolean hasCardIdValid(@RequestBody String cardId) { 
     return memberService.hasCardIdValid(cardId); 
    } 
} 

在另一個春天啓動應用程序,我打電話hasCreditCard方法

@Autowired 
    public GlobalScan(RestTemplateBuilder restTemplateBuilder, @Value("${main.server.url}") String mainServerUrl, @Value("${commerce.username}") String commerceUsername, @Value("${commerce.password}")String commercePassword) { 
     this.restTemplate = restTemplateBuilder.basicAuthorization(commerceUsername, commercePassword).rootUri(mainServerUrl).build(); 
    } 

I do a call with this code 

Map<String, String> vars = new HashMap<String, String>(); 
vars.put("cardId", cardId); 

boolean accessAllowed = restTemplate.getForObject("/rest/members/card/" , Boolean.class, vars); 

我得到這個消息

2016-11-02 16:20:50.601 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/rest/members/card/'; against '/login' 
2016-11-02 16:20:50.601 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/rest/members/card/'; against '/rest/**' 
2016-11-02 16:20:50.601 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /rest/members/card/; Attributes: [authenticated] 
2016-11-02 16:20:50.601 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.sprin[email protected]9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS 
2016-11-02 16:20:50.602 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.access.vote.AffirmativeBased  : Voter: org.sp[email protected]3d300693, returned: -1 
2016-11-02 16:20:50.602 TRACE 7139 --- [nio-8080-exec-1] ationConfigEmbeddedWebApplicationContext : Publishing event in org.springframework.boot[email protected]2bdd8394: org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /rest/members/card/] 
2016-11-02 16:20:50.606 DEBUG 7139 --- [nio-8080-exec-1] o.s.s.w.a.ExceptionTranslationFilter  : Access is denied (user is anonymous); redirecting to authentication entry point 

org.springframework.security.access.AccessDeniedException: Access is denied 
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-4.1.1.RELEASE.jar:4.1.1.RELEASE] 

在我的主應用程序中,我使用表單登錄來連接到應用程序,就像您在春季安全中看到的一樣配置。

從我的其他應用程序如何調用無窗體登錄ws?

試着撥打WS與此

final RequestConfig config = RequestConfig.custom().setConnectTimeout(timeout * 1000).setConnectionRequestTimeout(timeout * 1000).setSocketTimeout(timeout * 1000).build(); 

final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); 
credentialsProvider.setCredentials(new AuthScope("http://localhost", 8080, AuthScope.ANY_REALM), new UsernamePasswordCredentials("bob", "smith")); 
final CloseableHttpClient client = HttpClientBuilder.create().setDefaultRequestConfig(config).setDefaultCredentialsProvider(credentialsProvider).build(); 

final ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(client); 
RestTemplate restTemplate = new RestTemplate(requestFactory); 

ResponseEntity<MemberDto> member = restTemplate.getForEntity("http://localhost:8080/rest/members/1", MemberDto.class); 

結果:http://pastebin.com/psNKPUtM

+0

我不知道這將解決你的問題,但各種'@Enable ...'註釋往往是「禁用」春天開機默認值...這是真的痛苦......但有時你需要他們。嘗試刪除這些。 另外,如果你可以在你的測試類上顯示註釋以及restTemplate是如何配置的...... – xenoterracide

+0

我只使用EnableWebSecurity嘗試過,但它包含了EnableGlobalAuthentication和Configuration,但遇到同樣的問題。 restTemplate的配置如何顯示。我沒有測試課。 –

+0

當服務器應用程序接受表單登錄時,如何在Spring Boot客戶機中使用基本身份驗證? – sura2k

回答

1

春季安全的默認密碼是由以下屬性配置:security.user.password=YOUR_PASSWORD 這應該在你有你的主應用程序來完成安全配置以及您正在嘗試呼叫的內容。

You can change the password by providing a security.user.password. This and other useful properties are externalized via SecurityProperties (properties prefix "security").

所以,如果你沒有更新的財產,以匹配commerce.password春天密碼會拒絕你的授權,你會得到401默認情況下,它使用它打印到控制檯一些隨機生成的密碼開始時。 documentation

+0

commerce.username及其密碼在restTemplate中使用。這些信息是假設用於登錄系統的,與Spring安全生成的默認密碼無關。如果我的主系統有用戶x,y z ......我想當我打電話給系統時能夠使用它們。 –

+0

好的,那麼目前尚不清楚你的主應用程序正在發生什麼。您能否爲您的主應用打開TRACE日誌記錄級別,並在嘗試請求時檢查它的日誌記錄。 –

+0

現在,我會去放置一個斷點到FilterSecurityInterceptor中進行調試並遍歷,直到org.springframework.security.access.intercept.AbstractSecurityInterceptor.authenticateIfRequired() 我認爲這是由於某種原因您的匿名身份驗證返回的原因檢查你的標題。 也嘗試在認證= authenticationManager.authenticate(認證); 我希望它在應用程序重新啓動後第一次發送請求時被擊中。 –

1

您正在配置formLogin(),但您嘗試在RestTemplate中使用http Basic Auth。 對於通過HTTP REST的請求,我建議您更改配置爲使用基本身份驗證:

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

    http.authorizeRequests() 
      .antMatchers("/login").permitAll() 
      .antMatchers("/rest/**").authenticated(); 

    http.csrf().disable(); 
    http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint); 

    http.httpBasic(); 
    http.logout().logoutUrl("/logout"); 
    http.logout().logoutSuccessUrl("/"); 

    // CSRF tokens handling 
    //http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class); 
} 

如果你需要同時我認爲你可以配置。

+0

無法調用ws,錯誤:http://pastebin.com/psNKPUtM –

0
  1. 添加基本身份驗證,以現有配置

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
        http 
         .... 
        .and() 
        .formLogin() // <------ Keep this 
         .... 
        .and() 
        .httpBasic() // <------ Add BASIC Auth 
        .and() 
         .....; 
    } 
    
  2. 使用RestTemplate

    public static void main(String[] args) { 
        RestTemplate rest = new RestTemplate(new ArrayList(Arrays.asList(new MappingJackson2HttpMessageConverter()))); 
        HttpHeaders headers = new HttpHeaders(); 
        headers.set("Authorization", "Basic YOUR_BASE64_ENCODED_CREDENTIALS"); 
        MediaType applicationJson = new MediaType("application","json"); 
        headers.setContentType(applicationJson); 
        headers.setAccept(Collections.singletonList(applicationJson)); 
        ResponseEntity<YourResponseObject> resp = rest.exchange("http://URL/rest/yourendpoint", HttpMethod.GET, new HttpEntity<String>("parameters", headers), YourResponseObject.class); 
    
        System.out.println(resp.getBody()); 
    

    }

YOUR_BASE64_ENCODED_CREDENTIALS =>如果使用U編寫一個簡單的客戶端在Java 8中,您可以使用java.util.Base64,否則使用commons-codec來完成該操作或其他操作。

更新: 春天開機參考:http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#jc-httpsecurity

+0

試圖同時使用,但表單登錄停止工作...看起來像密碼不工作...需要發送帶有授權的標頭否則不起作用... –

+0

我剛剛測試了我在這裏提出的建議。有效。另請參閱Spring Boot文檔。看起來它是默認的自動配置:http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#jc-httpsecurity。您正在使用哪種彈簧安全和彈簧啓動版本?你有自定義auth過濾器嗎? – sura2k

+0

無論如何,在非彈簧啓動應用程序中,您必須使用兩個單獨的具有'@ Order'的'@ Configuration'來保護具有不同配置的**兩個單獨端點**,例如formLogin()和httpBasic(),但它是這裏不重要,因爲你想支持兩者。 – sura2k