工程实践
使用 jwt 实现用户认证
源代码地址 jwt 介绍 什么是 jwt:jwt 全称是 jsonwebtoken,本质上是一个 token(秘钥),就像去电影院看电影,你得拿一张票,这张票有时间限制,区域限制,使用人数限制,token 就像一个电影票,必须满足合适的时间、区域、人数,才能“通过”。 jwt 依赖的库:kow-jwt(jsonwebtoken 的中间件),jsonwebtoken(用户生成 token ) jwt
源代码地址 jwt 介绍 什么是 jwt:jwt 全称是 jsonwebtoken,本质上是一个 token(秘钥),就像去电影院看电影,你得拿一张票,这张票有时间限制,区域限制,使用人数限制,token 就像一个电影票,必须满足合适的时间、区域、人数,才能“通过”。 jwt 依赖的库:kow-jwt(jsonwebtoken 的中间件),jsonwebtoken(用户生成 token ) jwt
server/jw.js
async function tokenError(ctx, next) {
try {
const token = ctx.header.authorization
if (token) {
try {
let payload = await verify(token.split(' ')[1], 'key1')
ctx.user = {
name: payload.name,
id: payload.id
}
} catch (error) {
console.log('token verify fail: ', error)
}
}
await next()
} catch (error) {
if (error.status === 401) {
ctx.status = 401
ctx.body = {
success: 1,
message: '认证失败'
}
} else {
ctx.status = 404
ctx.body = {
success: 1,
message: '语法错误或路径错误'
}
}
}
}
router.get('/login', async ctx => {
const userToken = {
name: 'Jen',
id: '01'
}
const token = jwt.sign(userToken, 'key1', {
expiresIn: '2h'
})
ctx.body = {
success: 0,
token: token,
message: '登录成功'
}
})
router.get('/logout', async ctx => {
ctx.body = {
success: 0,
message: '退出成功'
}
})
router.get('/getdata', async ctx => {
ctx.body = {
success: 0,
message: 'getdata的get方式为忽略token判断的路由'
}
})
router.get('/userInfo', async ctx => {
let token = ctx.header.authorization
ctx.body = {
success: 0,
message: token
}
})
app.use(tokenError)
app.use(
koaJwt({
secret: 'key1'
}).unless({
path: [/\/getdata/, /\/logout/, /\/login/]
})
)
src/http2/http.js
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
axios.defaults.timeout = 20000
// 手动设置Authorization头
axios.interceptors.request.use(
config => {
const token = localStorage.getItem('HAS_SET_TOKEN')
if (token) {
// Bearer是JWT的认证头部信息
config.headers.common['Authorization'] = 'Bearer ' + token
}
return config
},
error => {
return Promise.reject(error)
}
)
// 添加一个注射器
axios.interceptors.response.use(
response => {
return response
},
error => {
return Promise.reject(error)
}
)
// 这是登录接口
const loginApi = '/api/login'
// 这是获取用户信息接口
const getUserInfoApi = '/api/userInfo'
// 这是过滤后的接口
const getDataApi = '/api/getdata'
// 这是首页
const loginOutApi = '/api/logout'
config/index.js
module.exports = {
dev: {
'/api': {
target: 'http://127.0.0.1:1111',
changeOrange: true,
pathRewrite: {
'^/api': ''
}
}
}
}
main.js
axios.interceptors.response.use(
response => {
return response
},
error => {
if (error.response.status === 401) {
router.push('/login')
} else {
}
return Promise.catch(error)
}
)
src/router/index.js
routes: [
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/logout',
name: 'logout',
component: Logout,
meta: {
requireAuth: true
}
},
{
path: '/userInfo',
name: 'GetUserInfo',
component: GetUserInfo,
meta: {
requireAuth: true
}
},
{
path: '/getdata',
name: 'GetData',
component: GetData,
meta: {
requireAuth: false
}
}
]
可以看出/login 是登录页面,所以不需要判断是否需要重定向,getdata 是过滤的接口,所以也不用判断是否需要重定向
// to即将要进入的路由
// from导航要离开的路由
// next next()是进行管道中的下一个钩子,如果全部钩子执行完了,则导航的状态就是 confirmed ;next("/login")路由跳转
router.beforeEach((to, from, next) => {
if (to.meta.requireAuth) {
const token = localStorage.getItem('HAS_SET_TOKEN')
if (token && token !== 'null') {
next()
} else {
next('/login')
}
} else {
next()
}
})
src/components/login.vue
http.login().then(res => {
if (res.success == 0) {
this.msg = '登录成功'
localStorage.setItem('HAS_SET_TOKEN', res.token)
}
})
src/components/logout.vue
if (res.success == 0) {
this.msg = res.message
localStorage.removeItem('HAS_SET_TOKEN')
}
暂无评论
确认操作
请再次确认编辑图片
待上传图片 (剩余 0 张)
项目详情
确认评论邮箱
邀请制评论