最近项目重构,登录逻辑大改,安全机制增强,需从初始登录api的响应头里获取Cookie持久化,然后添加到之后api的请求头里,以下是基于Retrofit和Kotlin的实现步骤:
1.获取Cookie
class ResponseInterceptor :Interceptor{
companion object {
const val cookie:String = "Set-Cookie"
}
override fun intercept(chain: Interceptor.Chain?): Response? {
val request = chain?.request()?:return null
val response = chain.proceed(request)
val cookies = mutableListOf<String>()
response.headers("Set-Cookie").run {
if (isNotEmpty()){
forEach {
cookies.add(it)
LogUtil.w("Set-Cookie",it)
}
Hawk.put(cookie,cookies)//本地持久化,过期问题此处没处理
}
}
return response
}
}
首次请求中从响应头中拿到"Set-Cookie",返回的是一个集合cookies,打印出来是这个:
session_name=MTUzMTIyNTQ2MXxOd3dBTkUxQ056SkNWazVQTlROU1NVdFJSMXBZVTFveVJsZEhOek5QVkVGSVZreFpWVm96VGtoQlNWaENWVXREVmpkSlZsSk5Na0U9fHdNeeYckxcr8EpO5j62h6CyLMB4h_gcrR_g7fcE94kU; Path=/; Expires=Wed, 11 Jul 2018 12:24:21 GMT; Max-Age=86400
可以看出这个Cookie中包含4个信息,但是集合大小位1,难道是服务器自己处理拼接成一个了吗 ,分别如下:
- session-name
- Path
- Expires
- Max-Age
2.添加Cookie
class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val builder: Request.Builder = chain.request().newBuilder()
var strigBuilder:StringBuilder ? = null
Hawk.get<MutableList<String>>(ResponseInterceptor.cookie, mutableListOf()) //取出上一步中存储的Cookie
.run {
if (isNotEmpty()) {
forEach {
strigBuilder?.append(it)!!.append(";")
}
strigBuilder?.replace(strigBuilder.length,strigBuilder.length+1,"")//替换掉最后一个";"
builder.header("Cookie", strigBuilder.toString())
}
}
val request = builder.build()
return chain.proceed(request)
}
}
3.为Retrofit 里的OkHttpClient添加以上两个拦截器
private fun initOkHttpClient() {
val sslParams = HttpsUtils.getSslSocketFactory(arrayOf(okio.Buffer()
.writeUtf8(ApiConstants.CER_DCOIN).inputStream()), null, null)
if (mOkHttpClient == null) {
//设置Http缓存
val cache = Cache(File(ChainUpApp.appContext.cacheDir, "HttpCache"), (1024 * 1024 * 10).toLong())
mOkHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
.cache(cache)
.addInterceptor(ResponseInterceptor())//获取Cookie的拦截器
.addInterceptor(HeaderInterceptor())// 添加Cookie的拦截器
.addNetworkInterceptor(CacheInterceptor())
.retryOnConnectionFailure(true)
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.protocols(Collections.singletonList(Protocol.HTTP_1_1))
.build()
}
}
其实Cookie主要应用于Web应用与服务器的交互,但是为了使用同一套接口和安全的考虑,公司的App端也引入了Cookie机制
- Cookie的用途
因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两瓶饮料。最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么,所以Cookie就是用来绕开HTTP的无状态性的“额外手段”之一。服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。
- Cookie的缺陷
- Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
- 由于在HTTP请求中的Cookie是明文传递的,所以安全性成问题,除非用HTTPS。
- Cookie的大小限制在4KB左右,对于复杂的存储需求来说是不够用的。
网友评论