restTemplatebuider

时间:2016-10-31 00:13:50

标签: spring spring-security spring-boot resttemplate spring-restcontroller

我使用弹簧靴和弹簧安全。

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

@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.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@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.springframework.security.web.access.expression.WebExpressionVoter@3d300693, returned: -1
2016-11-02 16:20:50.602 TRACE 7139 --- [nio-8080-exec-1] ationConfigEmbeddedWebApplicationContext : Publishing event in org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@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]

在我的主应用程序中,我使用表单登录连接到应用程序,就像您在spring安全配置中看到的那样。

从我的其他应用程序如何在没有表单登录的情况下调用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

3 个答案:

答案 0 :(得分:1)

spring security中的默认密码由以下属性配置:security.user.password=YOUR_PASSWORD 这应该在您的主应用程序中完成,您可以在其中进行安全配置并尝试呼叫。

  

您可以通过提供security.user.password来更改密码。   这个和其他有用的属性通过外部化   SecurityProperties(属性前缀“security”)。

所以,如果你没有更新属性以匹配commerce.password中的密码,spring将拒绝你的授权,你将获得401.默认情况下,它会使用一些随机生成的密码,它会在启动时打印到控制台。 documentation

答案 1 :(得分: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);
}

如果您需要两者,我认为您可以配置两者。

答案 2 :(得分:0)

  1. 将BASIC身份验证添加到现有配置

    @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());
    

    }

  3. YOUR_BASE64_ENCODED_CREDENTIALS =&gt;如果使用Java 8,您可以使用java.util.Base64,否则使用commons-codec来执行此操作或其他操作。

    <强>更新 Spring引用引用:http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#jc-httpsecurity