1、withCredentials
修改类型定义:
interface AxiosRequestConfig {
// ...
withCredentials?: boolean
}
修改实现
export default function xhr(config: AxiosRequestConfig): AxiosPromise {
return new Promise((resolve, reject) => {
// method和data可能没有, 所以给出默认值
const {
url,
method = 'get',
data = null,
headers,
responseType,
timeout,
cancelToken,
withCredentials
} = config
// ...
if (withCredentials) {
request.withCredentials = withCredentials
}
})
}
2、CSRF防御
CSRF的防御手段有很多,比如验证请求的referer,但是referer是可以伪造的,所以杜绝此类攻击的一种方式是服务器要求每次请求都包含一个token,这个token不在前端生成,而是在我们每次访问站点的时候生成,并通过set-cookie的方式保存在客户端,然后客户端发送请求的时候,从cookie中对应的字段独处token,然后添加到请求headers中。这样服务器就可以从请求headers中读取这个token并验证。由于这个token是很难伪造的,所以就能区分这个请求是否是用户正常发起的。
对于我们的ta-axios库,我们要自动把这几件事做了,每次发送请求的时候,从cookie中读取对应的token值,然后添加到请求headers中。我们允许用户配置xsrfCookieName表示存储token的cookie名称,xsrfHeaderName表示请求headers中token对应的header名称。
axios.get('/more/get',{
xsrfCookieName: 'XSRF-TOKEN', // default
xsrfHeaderName: 'X-XSRF-TOKEN' // default
}).then(res => {
console.log(res)
})
我们提供xsrfCookieName和xsrfHeaderName的默认值,当然用户也可以根据自己的需求在请求中去配置xsrfCookieName和xsrfHeaderName。
代码实现
- 修改定义
interface AxiosRequestConfig {
//...
xsrfCookieName?: string,
xsrfHeaderName?: string
}
- 修改默认配置
const defaults: AxiosRequestConfig = {
// ...
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN'
}
接下来我们要做3件事
1、首先判断如果配置withCredentials为true或者是同源请求,我们才会在请求headers中添加xsrf相关字段;
2、如果判断成功,尝试从cookie中读取xsrf的token值;
3、如果能读到,则把它添加到请求headers的xsrf的相关字段中。
- 同源判断
helpers/url.ts
interface URLOrigin {
protocol: string,
host: string
}
const urlParsingNode = document.createElement('a')
const currentOrigin = resolveURL(window.location.href)
function resolveURL(url: string): URLOrigin {
urlParsingNode.setAttribute('href', url)
const { protocol, host } = urlParsingNode
return {
protocol,
host
}
}
function isURLSameOrigin(requestURL: string): boolean {
const parsedOrigin = resolveURL(requestURL)
return currentOrigin.protocol === parsedOrigin.protocol && currentOrigin.host === parsedOrigin.host
}
- cookie获取
cookie.ts
const cookie = {
read(name: string): string | null {
const match = document.cookie.match(new RegExp('(^|;\s*)(' + name + ')(=[^;]*)'))
return match ? decodeURIComponent(match[3]) : null
}
}
export default cookie
修改xhr.ts
export default function xhr(config: AxiosRequestConfig): AxiosPromise {
return new Promise((resolve, reject) => {
const {
// ...
xsrfCookieName,
xsrfHeaderName
} = config
//...
if ((withCredentials || isURLSameOrigin(url!)) && xsrfCookieName) {
const xsrfValue = cookie.read(xsrfCookieName)
headers[xsrfHeaderName!] = xsrfValue
}
// ...
})
}
demo
import axios, { Canceler } from '../../src/index'
const instance = axios.create({
xsrfCookieName: 'XSRF-TOKEN-D',
xsrfHeaderName: 'X-XSRF-TOKEN-D'
})
instance.post('/api/extend/post').then(res => {
console.log(res)
})
至此,我们实现了XSRF防御相关功能。接下来我们来实现ts-axios对上传和下载的支持
网友评论