JWT介绍
JSON Web Token是目前最为流行的跨域认证解决方案
如何获取:在使用 JWT 身份验证中,当用户使用其凭据成功登录时,将返回 JSON Web Token(令牌)

登录成功之后,服务器会返回 token
作用: 允许用户访问使用该令牌(token)允许的路由、服务和资源

首页-页面访问控制
在访问特定页面的时候,根据是否登录来决定是否允许访问

核心步骤:
- 抽取校验函数(多个页面需要使用)
- 判断token(缓存中的token)
- 提示用户并跳转登录页
- 页面调用(目前考虑首页即可)
关键代码:
common.js
1 2 3 4 5 6 7 8 9 10 11 12 13
| function checkLogin() { const token = localStorage.getItem('token') if (token === null) { showToast('请先登录') setTimeout(() => { location.href = 'login.html' }, 1500) } }
|
index.js
首页-用户名渲染
渲染缓存中的用户名
需求:

核心步骤:
- 抽取渲染函数(多页面使用)
- 读取并渲染用户名(缓存中)
- 页面调用函数(目前考虑首页)
关键代码:
common.js
1 2 3 4 5 6 7
| function renderUsername() { const username = localStorage.getItem('username') document.querySelector('.username').innerText = username }
|
index.js
首页-退出登录
完成首页退出登录操作
需求:
- 点击退出按钮,删除缓存数据(token,用户名)
- 返回登录页

核心步骤:
- 抽取退出登录函数(复用)
- 绑定点击事件
- 删除缓存并跳转登录页(token,用户名)
- 页面调用(目前考虑首页)
关键代码:
common.js
1 2 3 4 5 6 7 8 9 10 11
| function registerLogout() { document.querySelector('#logout').addEventListener('click', () => { localStorage.removeItem('username') localStorage.removeItem('token') location.href = 'login.html' }) }
|
index.js
首页-统计数据
获取首页统计数据并渲染
需求:
- 调用接口获取数据并渲染

数据接口:
- 统计数据接口需要登录才可以调用
- 调用时需要在请求头中携带token

axios设置请求头:
- headers属性设置对象
- key:根据文档设置,比如
Authorization
- value:携带到服务器的值
1 2 3 4 5 6
| axios({ url: '/dashboard', headers: { Authorization: 'token' } })
|
核心步骤:
- 根据文档调用接口
- 渲染数据
关键代码:
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async function getData() { const token = localStorage.getItem('token') const res = await axios({ url: '/dashboard', headers: { Authorization: token } }) const overview = res.data.data.overview
Object.keys(overview).forEach(key => { document.querySelector(`.${key}`).innerText = overview[key] }) }
getData()
|
首页-登录状态失效
首页-登录状态失效
需求:
- 调用接口时,token
- 有效:正常调用
- 无效: 提示用户,清除缓存,返回登录页

核心步骤:
- 判断token失效(401状态码)
- 删除缓存并提示用户
- 返回登录页
- **注意:**可以通过修改缓存中的token模拟失效,默认失效时间(2个小时)
关键代码:
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| async function getData() { const token = localStorage.getItem('token') try { const res = await axios({ url: '/dashboard', headers: { Authorization: token } }) const overview = res.data.data.overview
Object.keys(overview).forEach(key => { document.querySelector(`.${key}`).innerText = overview[key] }) } catch (error) { if (error.response.status === 401) { localStorage.removeItem('username') localStorage.removeItem('token') showToast('请重新登录')
setTimeout(() => { location.href = 'login.html' }, 1500) } }
}
getData()
|
axios-拦截器
作用: 请求发送之前,响应回来之后执行一些 公共 的逻辑

- 注册之后,调用接口
- 请求发送时–》执行请求拦截器–》服务器
- 服务器响应内容–》执行响应拦截器–》接收数据
axios请求拦截器-统一设置token
通过请求拦截器统一设置token
需求:
- 通过请求拦截器统一设置token
- 设置一次之后后续调用接口不用单独设置
请求拦截器-基本写法:
1 2 3 4 5 6 7 8 9 10
| axios.interceptors.request.use(function (config) { return config; }, function (error) { return Promise.reject(error); });
|
核心步骤:
- 添加请求拦截器
- 统一设置token
- 移除首页对应逻辑
关键代码:
commons.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
axios.interceptors.request.use(function (config) { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config; }, function (error) { return Promise.reject(error); });
|
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| async function getData() { try { const res = await axios({ url: '/dashboard', }) const overview = res.data.data.overview
Object.keys(overview).forEach(key => { document.querySelector(`.${key}`).innerText = overview[key] }) } catch (error) { if (error.response.status === 401) { localStorage.removeItem('username') localStorage.removeItem('token') showToast('请重新登录')
setTimeout(() => { location.href = 'login.html' }, 1500) } } }
|
axios响应拦截器-统一处理token失效
axios响应拦截器-统一处理token失效
需求:
- 通过 axios响应拦截器-统一处理token失效

响应拦截器-基本写法:
1 2 3 4 5 6 7 8 9 10 11
| axios.interceptors.response.use(function (response) { return response; }, function (error) { return Promise.reject(error); });
|
核心步骤:
- 添加响应拦截器
- 统一处理token失效
- 移除首页对应逻辑
关键代码:
common.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
axios.interceptors.response.use(function (response) { return response; }, function (error) { if (error.response.status === 401) { showToast('请重新登录') localStorage.removeItem('token') localStorage.removeItem('username') setTimeout(() => { location.href = 'login.html' }, 1500) } return Promise.reject(error); });
|
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| async function getData() { const res = await axios({ url: '/dashboard', }) const overview = res.data.data.overview
Object.keys(overview).forEach(key => { document.querySelector(`.${key}`).innerText = overview[key] }) }
|
axios响应拦截器-数据剥离
axios响应拦截器-数据剥离
需求:
axios响应拦截器-数据剥离
页面中使用数据时少写一个data


核心步骤:
- 剥离data属性(响应拦截器)
- 调整数据使用逻辑(登录,注册,首页)
关键代码:
commons.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
axios.interceptors.response.use(function (response) { return response.data; }, function (error) { if (error.response.status === 401) { showToast('请重新登录') localStorage.removeItem('token') localStorage.removeItem('username') setTimeout(() => { location.href = 'login.html' }, 1500) } return Promise.reject(error); });
|
index.js
:移除多余的.data
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| async function getData() { const res = await axios({ url: '/dashboard', }) const overview = res.data.overview
Object.keys(overview).forEach(key => { document.querySelector(`.${key}`).innerText = overview[key] }) }
|
register.js
:移除多余的.data
,try
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| document.querySelector('#btn-register').addEventListener('click', async () => { const form = document.querySelector('.register-form') const data = serialize(form, { empty: true, hash: true }) const { username, password } = data console.log(username, password) if (username === '' || password === '') { showToast('用户名和密码不能为空') return }
if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) { showToast('用户名的长度为8-30,密码的长度为6-30') return }
try { const res = await axios.post('/register', { username, password }) showToast(res.message) } catch (error) { showToast(error.response.data.message) } })
|
login.js
:移除多余的.data
,try
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| document.querySelector('#btn-login').addEventListener('click', async () => { const form = document.querySelector('.login-form') const data = serialize(form, { empty: true, hash: true }) console.log(data) const { username, password } = data if (username === '' || password === '') { showToast('用户名和密码不能为空') return }
if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) { showToast('用户名长度8-30,密码长度6-30') return }
try { const res = await axios.post('/login', { username, password }) showToast(res.message) localStorage.setItem('token', res.data.token) localStorage.setItem('username', res.data.username) setTimeout(() => { location.href = './index.html' }, 1500)
} catch (error) { showToast(error.response.data.message) }
})
|