有关认证
https://blog.csdn.net/rioalian/article/details/77100633
代码
import org.apache.http.auth.AuthScope
import org.apache.http.auth.UsernamePasswordCredentials
import org.apache.http.client.CredentialsProvider
import org.apache.http.client.config.RequestConfig
import org.apache.http.conn.ssl.DefaultHostnameVerifier
import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
import org.apache.http.conn.ssl.TrustAllStrategy
import org.apache.http.impl.client.BasicCredentialsProvider
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.ssl.SSLContexts
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.Resource
import java.security.KeyStore
import javax.net.ssl.SSLContext
@Configuration
@ConditionalOnProperty("httpclient.timeout")
@EnableConfigurationProperties(HttpClientProperties::class)
class HttpClientConfig(private val properties: HttpClientProperties) {
@Bean(destroyMethod = "close")
fun httpClient(sslContext: SSLContext?,
credentialsProvider: CredentialsProvider?): CloseableHttpClient {
val timeout = properties.timeout * 1000
val config = RequestConfig.custom()
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout)
.build()
return HttpClientBuilder.create()
.setSSLSocketFactory(SSLConnectionSocketFactory(
sslContext ?: SSLContext.getDefault(),
properties.supportedProtocols,
null,
if (properties.verifyHost) DefaultHostnameVerifier() else NoopHostnameVerifier()
))
.setDefaultCredentialsProvider(
credentialsProvider ?: BasicCredentialsProvider()
)
.setDefaultRequestConfig(config).build()
}
@Bean
@ConditionalOnProperty("httpclient.clientKeyStore")
fun ssLContext(): SSLContext {
val trustStore = properties.trustKeyStore?.let { getKeyStore(properties.trustKeyStoreType, it, properties.trustKeyStorePwd!!) }
val keyStore = getKeyStore(properties.clientKeyStoreType, properties.clientKeyStore!!, properties.clientKeyStorePwd!!)
return SSLContexts
.custom()
.loadTrustMaterial(trustStore, TrustAllStrategy().takeIf { trustStore == null })
.loadKeyMaterial(keyStore, properties.clientKeyPwd!!.readText().toCharArray())
.build()
}
@Bean
@ConditionalOnProperty("httpclient.basicAuthUser")
fun getCredentialsProvider(): CredentialsProvider {
val provider = BasicCredentialsProvider()
val scope = AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM)
val credentials = UsernamePasswordCredentials(properties.basicAuthUser, properties.basicAuthPwd)
provider.setCredentials(scope, credentials)
return provider
}
private fun getKeyStore(type: String, keyStorePath: Resource, keyStorePwd: Resource): KeyStore {
val keyStore = KeyStore.getInstance(type)
keyStore.load(keyStorePath.inputStream, keyStorePwd.readText().toCharArray())
return keyStore
}
}
@ConfigurationProperties("httpclient")
class HttpClientProperties {
var timeout = 0
var clientKeyStore: Resource? = null
var clientKeyStorePwd: Resource? = null
var clientKeyStoreType = "jks"
var clientKeyPwd: Resource? = null
var trustKeyStore: Resource? = null
var trustKeyStorePwd: Resource? = null
var trustKeyStoreType = "jks"
var supportedProtocols: Array<String>? = null
var basicAuthUser: String? = null
var basicAuthPwd: String? = null
var verifyHost = true
}
调用
以json形式
@Service
class Api(val svsSign: SvsSign,
val httpClient: CloseableHttpClient,
val config: Config) {
private val logger = LoggerFactory.getLogger(Api::class.java)
fun <T : Response> execute(request: Request, parseResponse: (String) -> T): T {
val httpPost = HttpPost(config.host)
httpPost.entity = StringEntity(Codecs.objToJsonString(RequestPayload(svsSign.signatureRequest(request))), Consts.UTF_8)
logger.info("send ${request.head.headTranCode} with extRefId: ${request.body.serialNo} request to api:\n ${Codecs.objToJsonString(request)}")
val httpResponse = httpClient.execute(httpPost)
val content = EntityUtils.toString(httpResponse.entity)
logger.info("receive raw response from api\n $content")
return parseResponse(content)
}
}
以xml形式
@Component
class Client(private val httpClient: CloseableHttpClient,
private val rail: Config.rail) {
val logger = LoggerFactory.getLogger(this.javaClass)
fun <T : Response> execute(request: Request, action: ActionType<T>, account: Config.railAccount): Response {
request.UID = account.userName
request.PWD = account.pwd
val signStr = request.getSignStr().plus(account.signatureKey)
request.rspSign = String(Hex.encodeHex(MessageDigest.getInstance("MD5").digest(signStr.toByteArray(Charsets.US_ASCII)), true))
val reqBody = MessageTransformer.toXML(request)
val result = simplePostReq(reqBody, action.name).content
return MessageTransformer.fromXML<Response>(result, action.elementName, action.responseClass as Class<Response>)
}
private fun simplePostReq(content: String, path: String): HttpResult {
val httpPost = HttpPost(rail.client.url)
httpPost.setHeader("Content-type", "text/xml;charset=utf-8");
httpPost.setHeader("SOAPAction", "http://tempuri.org/$path")
httpPost.entity = StringEntity(content, Charsets.UTF_8)
var resContent: String?
var response: HttpResponse?
try {
logger.info("\n ****** Sending request to ${rail.client.url} with content ******\n $content")
response = httpClient.execute(httpPost)
resContent = EntityUtils.toString(response.entity)
logger.info("\n ****** Received response ******\n ${getPrettyString(resContent, 2)}")
} catch (e: Exception) {
e.printStackTrace()
throw FailureException(Failure.of("Invoke rail service failed", e.message))
}
return HttpResult(response!!.statusLine.statusCode, resContent)
}
@Throws(Exception::class)
private fun getPrettyString(xmlData: String, indent: Int): String {
val transformerFactory = TransformerFactory.newInstance()
transformerFactory.setAttribute("indent-number", indent)
val transformer = transformerFactory.newTransformer()
transformer.setOutputProperty(OutputKeys.INDENT, "yes")
val stringWriter = StringWriter()
val xmlOutput = StreamResult(stringWriter)
val xmlInput = StreamSource(StringReader(xmlData))
transformer.transform(xmlInput, xmlOutput)
return xmlOutput.writer.toString()
}
private class HttpResult(var status: Int, var content: String?)
}