目錄
Server
Startup
egg-init --type=simple read-cookie-server
cd read-cookie-server && cnpm i
cnpm run dev # localhost:7001
- 測(cè)試
curl localhost:7001 # hi, egg
Router
vim app/router.js
'use strict';
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.post('/login', controller.auth.login);
};
Controller
vim app/controller/auth.js
'use strict';
const Controller = require('egg').Controller;
class AuthController extends Controller {
async login() {
const ctx = this.ctx;
ctx.session.user = 1;
ctx.body = { message: 'success' };
ctx.status = 200;
}
}
module.exports = AuthController;
vim config/config.default.js
// 省略了未修改的代碼
config.session = {
httpOnly: true,
encrypt: false,
};
config.security = {
csrf: {
enable: false,
},
};
// 省略了未修改的代碼
- 測(cè)試
curl -X POST localhost:7001/login # {"message":"success"}
CORS
cnpm i --save egg-cors
vim config/plugin.js
'use strict';
exports.cors = {
enable: true,
package: 'egg-cors',
};
vim config/config.default.js
// 省略了未修改的代碼
config.cors = {
credentials: true,
origin: 'http://localhost:8080',
allowMethods: 'HEAD,OPTIONS,GET,PUT,POST,DELETE,PATCH',
};
// 省略了未修改的代碼
關(guān)于egg.js更多參考Egg.js實(shí)戰(zhàn)
Client
Startup
vue create read-cookie-client
cd read-cookie-client && yarn serve
View
vim src/App.vue
<template>
<div id="app">
<div>
<button v-on:click="login">登錄</button>
<a>{{message}}</a>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
message: '',
}
},
methods: {
login() {
fetch('http://localhost:7001/login', { method: 'POST', credentials: 'include' })
.then(res => {
return res.json();
}).then(json => {
this.message = json;
}).catch(error => {
this.message = error;
});
},
}
}
</script>
<style>
</style>
- 測(cè)試
使用瀏覽器打開(kāi)http://localhost:8080
方法1
我們知道: 瀏覽器cookie是通過(guò)response的set-cookie header實(shí)現(xiàn)的 效果如下
那么是否可以通過(guò)fetch api的response獲取到cookie呢 代碼如下
vim src/App.vue
// 省略了未修改的代碼
methods: {
login() {
fetch('http://localhost:7001/login', { method: 'POST', credentials: 'include' })
.then(res => {
console.log(res.headers.get('content-type'));
console.log(res.headers.get('set-cookie'));
return res.json();
}).then(json => {
this.message = json;
}).catch(error => {
this.message = error;
});
},
}
// 省略了未修改的代碼
點(diǎn)擊登錄按鈕后 瀏覽器console打印結(jié)果如下
為什么fetch api無(wú)法獲取reponse的set-cookie header呢 解釋如下
The Set-Cookie header is on the forbidden header list:
https://fetch.spec.whatwg.org/#forbidden-response-header-nameResponses do not include forbidden headers:
https://fetch.spec.whatwg.org/#concept-filtered-response-basic
因此我們知道
方法1: 通過(guò)fetch api response獲取cookie不可行!
方法2
我們知道: 如果cookie的HttpOnly屬性設(shè)置為false 那么就可以通過(guò)document.cookie獲取到cookie
vim src/App.vue
<template>
<div id="app">
<div>
<button v-on:click="login">登錄</button>
<a>{{message}}</a>
</div>
<div>
<button v-on:click="getCookie">獲取cookie</button>
<a>{{cookie}}</a>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
message: '',
cookie: '',
}
},
methods: {
login() {
fetch('http://localhost:7001/login', { method: 'POST', credentials: 'include' })
.then(res => {
console.log(res.headers.get('content-type'));
console.log(res.headers.get('set-cookie'));
return res.json();
}).then(json => {
this.message = json;
}).catch(error => {
this.message = error;
});
},
getCookie() {
this.cookie = document.cookie ? document.cookie : '獲取失敗';
},
}
}
</script>
<style>
</style>
- 測(cè)試
使用瀏覽器打開(kāi)http://localhost:8080
點(diǎn)擊"登錄"后點(diǎn)擊"獲取cookie" 結(jié)果"獲取失敗" 效果如下
此時(shí) 修改Server代碼將HttpOnly設(shè)置為false 代碼如下
vim config/config.default.js
// 省略了未修改的代碼
config.session = {
httpOnly: false,
encrypt: false,
};
// 省略了未修改的代碼
- 測(cè)試
使用瀏覽器打開(kāi)http://localhost:8080
點(diǎn)擊"登錄"后點(diǎn)擊"獲取cookie"到cookie 效果如下
但是此時(shí)有面臨XSS攻擊的危害 因此
方法2: 通過(guò)將cookie的HttpOnly屬性設(shè)置為false獲取cookie不可行!
小結(jié)
關(guān)于cookie操作涉及三個(gè)主體
Javascript App <-> Browser <-> Server
安全的cookie設(shè)計(jì) 基于Browser和Server而非Javascript
這也正是上述兩種方法都無(wú)法獲取cookie的原因