SpringBoot2.1.5.RELEASE .使用restTemplate访问Rest服务发送POST请求为什么无法通过验证?

headers定义如下:

 @Bean
    public HttpHeaders getHttpHeaders(){
        HttpHeaders httpHeaders = new HttpHeaders();
        String authInfo = "admin:123456";
        byte [] encodedAuthInfo = Base64.getEncoder().encode(authInfo.getBytes(Charset.forName("US-ASCII")));
        authInfo = "Basic " + new String(encodedAuthInfo);
        httpHeaders.set("Authorization" , authInfo);//将授权信息保存到Header中
 
        return httpHeaders;
    }

发送POST请求

restTemplate.exchange(ADD_DEPT_URL,HttpMethod.POST,new HttpEntity(dept,this.httpHeaders),Object.class).getBody();

出现:org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 null
发送GET请求可以通过验证
配置文件:

spring:
  security:
      user:
        name: admin   #认证用户名
        password: 123456 #认证密码
        roles: #授权角色
        - USER
        - ADMIN

之前的SpringBoot1.5.4.RELEASE没有这个问题

试试看。

restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));
restTemplate.getForObject(url, String.class);

说实话,我也不熟悉springsecurity

POST 请求还是不能通过验证,但是不用POST Rest服务就无法使用这个注解@RequestBody接收参数了。
是因为 [SpringBoot2.1.5.RELEASE] 有Bug吗:scream:

SpringBoot2.1.5.RELEASE 用的是Spring Security5 。
在Spring Security5这个版本认证中需要使用PasswordEncoder,

	@Bean//配置了@Bean相当于配置了auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder() ); 或auth.userDetailsService(userServiceDetails).passwordEncoder(new BCryptPasswordEncoder())
        //客户端输入的密码会被此加密器加密
	public PasswordEncoder getPasswordEncoder() {
		return new BCryptPasswordEncoder();
	}
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("admin").password(getPasswordEncoder().encode("123456")).roles("USER");//而此处的密码加密相当于给数据库中的已经注册用户密码加密
	}

如果服务提供者不配置passwordEncoder,消费者通过RestTemplate访问会导致401错误,而至于GET请求正常,POST请求异常,是因为服务提供者设置了CSRF保护。

但CSRF是一种依赖web浏览器持久化授权(例如cookie或者HTTP授权,也就是基于已登录)的一种攻击,在本处使用RestTemplate自然不在这个范围,另外服务提供者通常设置session无状态,登陆都登陆不了,更谈不上CSRF攻击,所以可以设置关闭保护: .csrf().disable();,然后消费者访问时就没有401错误了!

1 Like