上一章咱們介紹了「bug信息收集系統」的搭建和基本使用,本章將介紹它的高級用法,並對源碼進行解析。主要分爲如下三個部分:html
咱們先來明確目前遇到的問題前端
leanCloud的配置信息是不可避免會被泄漏的(即便經過後端返回,黑客也能夠查看接口拿到配置信息),那咱們怎麼在配置信息不安全的狀況下,仍保持數據的安全性,不讓黑客獲取咱們上報的數據呢?vue
咱們能夠經過leanCould的訪問控制列表(ACL 機制)(Access Control List)來實現
其原理經過在leanCloud中設置不一樣的角色,併爲不一樣的角色設置不一樣的權限,來約束其行爲。具體流程以下:ios
這樣即便被黑客獲取了role_write角色的配置信息,也僅能添加新數據,不能修改,更不能查看。
而role_read角色是對於內部人員使用的,沒有信息安全問題。從而解決數據安全問題。ajax
第一步,調用leanCloud方法添加兩個用戶角色。axios
右側展現的,就是咱們剛建立的兩個角色後端
<script src="https://cdn1.lncld.net/static/js/av-min-1.2.1.js"></script> <script> AV.init({ appId: 'xxx', appKey: 'xxx', }); // 註冊角色 function signup() { var user = new AV.User(); user.setUsername('role_write'); user.setPassword('xxx'); user.signUp().then(function (loggedInUser) { alert('註冊成功') console.log(loggedInUser); }); } </script>
第二步,關閉leanCloud使用js添加角色的權限api
第三步,設置bug類的訪問權限緩存
第四步,在vue組件中,添加登陸語句。安全
方法很簡單,在初始化後面加一條登陸語句便可
AV.init({ appId: 'xxx', appKey: 'xxx', }) AV.User.logIn('role_write', 'xxx')
原理很簡單,檢測當前頁面URL是否匹配特定的域名前綴。
// 獲取運行環境 getRuntimeEnv() { let envObj = { dev: 'xxx', test: 'xxx', pre: 'xxx', prod: 'xxx', } for (let key in envObj) { if (location.href.indexOf(envObj[key]) !== -1) { return key } } return 'local' }
作這個檢測,是由於在vue項目開發中,熱編譯會導致部分代碼會被從新加載。致使leanCloud屢次加載而報錯。故須要在這裏先檢測是否已經被加載過,再去進行初始化操做。
init() { this.resetAjax() // 覆寫ajax this.$root.__proto__.$addCustomData = this.addCustomData.bind(this) // 註冊全局函數 this.$root.__proto__.$clearCustomData = this.clearCustomData.bind(this) this.$root.__proto__.$addGlobalData = this.addGlobalData.bind(this) this.$root.__proto__.$clearGlobalData = this.clearGlobalData.bind(this) window.$collectData = this.reportDate.bind(this) if (!AV._config.applicationId) { // 檢測AV是否已經被初始化過 AV.init({ appId: 'I7QMGWueNtd27ILAiMQqUAzI-gzGzoHsz', appKey: 'WRoSIQ8hSGLq9xLbaWDe9f7y', }) AV.User.logIn('XtRuRZtca-for-add', 'Xw8XFNAidgEbJefXnCuG') } }
ajax覆寫的原理,
首先經過變量保存原始的window.XMLHttpRequest,及其原型鏈上的open,send,setRequestHeader方法
let originXHR = window.XMLHttpRequest let originOpen = originXHR.prototype.open let originSend = originXHR.prototype.send let originSetRequestHeader = originXHR.prototype.setRequestHeader
覆寫 window.XMLHttpRequest 構造函數
這裏介紹一下每一個覆寫函數的中作了什麼操做
最後是監聽接口loadend事件,即接口響應事件
若是你們對JS的繼承有印象的話,會發現,這個作法與JS的實例繼承相似,在內部生產父類的實例,對實例進行一系列操做後,返回這個實例
// 重寫AJAX resetAjax() { if (window._hadResetAjax) { // 若是已經重置過,則再也不進入。解決開發時局部刷新致使從新加載問題 return } window._hadResetAjax = true let originXHR = window.XMLHttpRequest let originOpen = originXHR.prototype.open let originSend = originXHR.prototype.send let originSetRequestHeader = originXHR.prototype.setRequestHeader // 重置事件 window.XMLHttpRequest = () => { let ajaxData = {} // 整個ajax數據,收集數據時用 let realXHR = new originXHR() // 重置操做函數,獲取請求數據 realXHR.open = (method, url, asyn) => { ajaxData.request = { method: method, url: url.split('?')[0], data: this.getParams(url), header: {}, } originOpen.call(realXHR, method, url, asyn) } // 重置設置請求頭的函數 realXHR.setRequestHeader = (header, value) => { ajaxData.request.header[header] = value originSetRequestHeader.call(realXHR, header, value) } // 重置操做函數,獲取請求數據 realXHR.send = (postData) => { ajaxData.request.timeout = realXHR.timeout ajaxData.request.responseType = realXHR.responseType if (postData) { ajaxData.request.data = typeof postData === 'string' ? this.getParams(`?${postData}`) : postData } try { // 防止timeout等報錯,形成程序阻塞 originSend.call(realXHR, postData) } catch (e) { console.log(e) } } // 監聽加載完成,獲取回覆的報文 realXHR.addEventListener('loadend', () => { ajaxData.response = realXHR.response if (ajaxData.request.url.indexOf('api.leancloud.cn') === -1) { this.ajaxList.push(ajaxData) if (this.ajaxHook) { // 外部執行鉤子 this.ajaxHook(ajaxData) && this.reportDate() } } }, false) return realXHR } },