一、背景
一些比较重要的微服务,我们暴露的接口可能会希望安全性更高一些,此时,我们会给这些接口增加一些鉴权,如比较简单且方便的鉴权方式Basic Auth鉴权,此时,针对这些有Basic Auth鉴权的接口,我们该如何写Feign,其实是通过覆盖Feign的默认配置来支持鉴权。
二、 步骤
FeignClient
的属性configuration
增加自定义配置Configuration.class
@FeignClient(name = "mytest-server", configuration = Configuration.class)
public interface Client {
//..
}
Configuration
如下(特别注意,别加@Configuration注解,避免扫包扫到导致给全局的Feign都增加了BasicAuthRequestInterceptor
拦截器):
/**
* basic验证配置
*/
@EnableConfigurationProperties({Properties.class})
public class Configuration {
@Autowired
private Properties properties;
public Configuration() {
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor(properties.getUsername(), properties.getPassword());
}
}
其中Properties.java
为
/**
* basic验证配置
*/
@ConfigurationProperties(prefix = "mytest")
@Data
public class Properties {
private String username;
private String password;
}
application.yaml
增加basic auth账号密码配置如下:
mytest:
username: test
password: 123456
三、源码解析
核心就是请求头上添加Authorization=Basic xxx
public class BasicAuthRequestInterceptor implements RequestInterceptor {
private final String headerValue;
/**
* Creates an interceptor that authenticates all requests with the specified username and password
* encoded using ISO-8859-1.
*
* @param username the username to use for authentication
* @param password the password to use for authentication
*/
public BasicAuthRequestInterceptor(String username, String password) {
this(username, password, ISO_8859_1);
}
/**
* Creates an interceptor that authenticates all requests with the specified username and password
* encoded using the specified charset.
*
* @param username the username to use for authentication
* @param password the password to use for authentication
* @param charset the charset to use when encoding the credentials
*/
public BasicAuthRequestInterceptor(String username, String password, Charset charset) {
checkNotNull(username, "username");
checkNotNull(password, "password");
this.headerValue = "Basic " + base64Encode((username + ":" + password).getBytes(charset));
}
/*
* This uses a Sun internal method; if we ever encounter a case where this method is not
* available, the appropriate response would be to pull the necessary portions of Guava's
* BaseEncoding class into Util.
*/
private static String base64Encode(byte[] bytes) {
return Base64.encode(bytes);
}
@Override
public void apply(RequestTemplate template) {
template.header("Authorization", headerValue);
}
}