spring 配置 Http请求账号密码验证功能

HttpRequester 类有构造方法,通过构造方法,加载http请求的参数。

public HttpRequester(int connectionRequestTimeout, int connectionTimeout, int socketTimeout, String 	defaultCharset, String proxyServer,HttpClientContext httpClientContext) {
	super();
	init(connectionRequestTimeout, connectionTimeout, socketTimeout, defaultCharset, proxyServer,httpClientContext);
}

private void init(
		   int connectionRequestTimeout ,int connectionTimeout ,int socketTimeout
		 , String defaultCharset ,String proxyServer , HttpClientContext httpClientContext
){
	this.httpClient = HttpClients.createDefault();

	Builder requestBuilder = RequestConfig.custom();
	requestBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
	requestBuilder.setConnectTimeout(connectionTimeout);
	requestBuilder.setSocketTimeout(socketTimeout);
	if (StringUtils.isNotBlank(proxyServer)) {
		requestBuilder.setProxy(HttpHost.create(proxyServer));
	}
	this.requestConfig = requestBuilder.build();
	this.responseHandler = new DefaultResponseHandler(Charset.forName(defaultCharset));
	this.httpClientContext = httpClientContext;
}

其中,需要有验证用户账号密码的代码,JAVA代码如下:

UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials("XXX", "123456");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST,AuthScope.ANY_PORT),usernamePasswordCredentials);
	
HttpClientContext httpClientContext = HttpClientContext.create();
httpClientContext.setCredentialsProvider(credentialsProvider);

以上JAVA代码,用spring配置bean方式实现。

此时,spring 配置构造方法为:

<bean id="httpRequester" class="com.champion.common.util.http.HttpRequester">
	<constructor-arg value="${httpRequester.connectionRequestTimeout}" type="int" />
	<constructor-arg value="${httpRequester.connectionTimeout}" type="int" />
	<constructor-arg value="${httpRequester.socketTimeout}" type="int" />
	<constructor-arg type="String" value="UTF-8" />
	<constructor-arg type="String"><null/></constructor-arg>
	<constructor-arg type="org.apache.http.client.protocol.HttpClientContext">
		<!-- 待完善 -->
	</constructor-arg>
</bean>

注:

  1. type为String时,可以省略不写。
  2. 配置参数数量要与构造函数的参数数量保持一致(构造函数有多个,不同数量对应不同构造函数,因此可以写多个配置,通过id来区分不同的配置的JAVA类)。
  3. <null/>表示为空值。
  4. Spring通过构造方法注入的四种方式
    1. 第一种方法:根据索引赋值,索引都是以0开头的:

       <constructor-arg index="0" value="3500" />
      
    2. 第二种方法:根据所属类型传值(根据顺序排的)

       <constructor-arg type="java.lang.Double" value="3500" />
      
    3. 第三种方法:根据参数的名字传值

       <constructor-arg name="salary" value="3500" />
      
    4. 第四种方法:直接传值(根据顺序排的)

       <constructor-arg  value="3500" />
      

继续:
查看类HttpClientContext,有工厂方法create,创建HttpClientContext对象

public static HttpClientContext adapt(final HttpContext context) {
    if (context instanceof HttpClientContext) {
        return (HttpClientContext) context;
    } else {
        return new HttpClientContext(context);
    }
}

public static HttpClientContext create() {
    return new HttpClientContext(new BasicHttpContext());
}

public HttpClientContext(final HttpContext context) {
    super(context);
}

public HttpClientContext() {
    super();
}

然后配置更新如下:

<bean id="httpRequester" class="com.champion.common.util.http.HttpRequester">
	<constructor-arg value="${httpRequester.connectionRequestTimeout}" type="int" />
	<constructor-arg value="${httpRequester.connectionTimeout}" type="int" />
	<constructor-arg value="${httpRequester.socketTimeout}" type="int" />
	<constructor-arg type="String" value="UTF-8" />
	<constructor-arg type="String"><null/></constructor-arg>
	<constructor-arg type="org.apache.http.client.protocol.HttpClientContext">
		<bean class="org.apache.http.client.protocol.HttpClientContext" factory-method="create">
			<!-- 待完善 -->
		</bean>
	</constructor-arg>
</bean>

继续,查看JAVA代码如下:

HttpClientContext httpClientContext = HttpClientContext.create();
httpClientContext.setCredentialsProvider(credentialsProvider);

需要有credentialsProvider参数,该参数在HttpClientContext里面可以通过get set获取,代码如下:

public CredentialsProvider getCredentialsProvider() {
    return getAttribute(CREDS_PROVIDER, CredentialsProvider.class);
}

public void setCredentialsProvider(final CredentialsProvider credentialsProvider) {
    setAttribute(CREDS_PROVIDER, credentialsProvider);
}

然后配置更新如下:

<bean id="httpRequester" class="com.champion.common.util.http.HttpRequester">
	<constructor-arg value="${httpRequester.connectionRequestTimeout}" type="int" />
	<constructor-arg value="${httpRequester.connectionTimeout}" type="int" />
	<constructor-arg value="${httpRequester.socketTimeout}" type="int" />
	<constructor-arg type="String" value="UTF-8" />
	<constructor-arg type="String"><null/></constructor-arg>
	<constructor-arg type="org.apache.http.client.protocol.HttpClientContext">
		<bean class="org.apache.http.client.protocol.HttpClientContext" factory-method="create">
			<property name="credentialsProvider">
				<!-- 待完善 -->
			</property>
		</bean>
	</constructor-arg>
</bean>

继续,查看JAVA代码如下:

CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

继续,查看BasicCredentialsProvider如下:

public class BasicCredentialsProvider implements CredentialsProvider {

private final ConcurrentHashMap<AuthScope, Credentials> credMap;


public BasicCredentialsProvider() {
    super();
    this.credMap = new ConcurrentHashMap<AuthScope, Credentials>();
}

@Override
public void setCredentials(
        final AuthScope authscope,
        final Credentials credentials) {
    Args.notNull(authscope, "Authentication scope");
    credMap.put(authscope, credentials);
}


private static Credentials matchCredentials(
        final Map<AuthScope, Credentials> map,
        final AuthScope authscope) {
    // see if we get a direct hit
    Credentials creds = map.get(authscope);
    if (creds == null) {
        // Nope.
        // Do a full scan
        int bestMatchFactor  = -1;
        AuthScope bestMatch  = null;
        for (final AuthScope current: map.keySet()) {
            final int factor = authscope.match(current);
            if (factor > bestMatchFactor) {
                bestMatchFactor = factor;
                bestMatch = current;
            }
        }
        if (bestMatch != null) {
            creds = map.get(bestMatch);
        }
    }
    return creds;
}

@Override
public Credentials getCredentials(final AuthScope authscope) {
    Args.notNull(authscope, "Authentication scope");
    return matchCredentials(this.credMap, authscope);
}

发现无法通过get set或者构造方式等方式加载credentialsProvider。

因此,新建JAVA类,代码如下(可以通过工厂方式注入该bean):

public class CredentialsProviders {
	public final static CredentialsProvider createUsernamePasswordCredentialsProvider(String username, String password,String authScopeHost,int authScopePort) {
		UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials(username, password);
		CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
		if(StringUtils.isBlank(authScopeHost)){
			authScopeHost = AuthScope.ANY_HOST;
		}
		if(authScopePort < 0){
			authScopePort = AuthScope.ANY_PORT;
		}
		credentialsProvider.setCredentials(new AuthScope(authScopeHost,authScopePort),
				usernamePasswordCredentials);
		return credentialsProvider;
	}
	public final static CredentialsProvider createUsernamePasswordCredentialsProvider(String username, String password) {
		return createUsernamePasswordCredentialsProvider(username, password,AuthScope.ANY_HOST,AuthScope.ANY_PORT);
	}
}

然后配置更新如下:

<bean id="httpRequester" class="com.champion.common.util.http.HttpRequester">
	<constructor-arg value="${httpRequester.connectionRequestTimeout}" type="int" />
	<constructor-arg value="${httpRequester.connectionTimeout}" type="int" />
	<constructor-arg value="${httpRequester.socketTimeout}" type="int" />
	<constructor-arg type="String" value="UTF-8" />
	<constructor-arg type="String"><null/></constructor-arg>
	<constructor-arg type="org.apache.http.client.protocol.HttpClientContext">
		<bean class="org.apache.http.client.protocol.HttpClientContext" factory-method="create">
			<property name="credentialsProvider">
				<bean class="com.champion.common.util.http.CredentialsProviders"
					factory-method="createUsernamePasswordCredentialsProvider">
					<constructor-arg value="${svn.username}" />
					<constructor-arg value="${svn.password}" />
				</bean>
			</property>
		</bean>
	</constructor-arg>
</bean>

自此,通过spring配置实现用户账号密码验证http请求的功能已经实现。

延伸阅读:
spring四种依赖注入方式
Spring通过构造方法注入的四种方式

原文地址:https://www.cnblogs.com/cuiyf/p/6912254.html