【JS】基于jwt认证的实现

起因

http是无状态协议,需要知道是哪一个用户,因此需要一种验证机制。随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。具体认证的实现过程如下:
【JS】基于jwt认证的实现

什么是jwt

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

jwt的组成

JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ


第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

jwt加密流程

1.前端发起登录请求

login({ commit }, userInfo) {

const { username, password } = userInfo

return new Promise((resolve, reject) => {

login({ username: username.trim(), password: password }).then(response => {

commit('SET_TOKEN', response.token)

setToken(response.token)

resolve()

}).catch(error => {

reject(error)

})

})

}

2.后端接受参数进行登录校验

this.app.jwt.sign({ username: username }, this.app.config.jwt.web.secret, { expiresIn: expiresIn })

如上后端代码使用了nodejs的egg框架,使用的是egg-jwt插件进行加密和解密;其中代码中的username为用户账号(id),secret则为加密的盐值(解密需要用到),expiresIn则为生成的token的有效时间。账号密码验证通过后,你可以自定你的加密内容(payload),其中示例代码加入了username。当然你还可以加入你的userInfo等,并且将生成的toekn返回到前端(思考:很多编程新手喜欢在登录成功之后直接返回了用户的信息,作者是不推荐这样做的;这里我们只返回token,前端拿到返回的token存储起来)

3.登陆成功后前端储存token

login({ username: username.trim(), password: password }).then(response => {

commit('SET_TOKEN', response.token)//登录成功之后存储token,你可以存在vuex或者local中

setToken(response.token)

resolve()

}).catch(error => {

reject(error)

})

jwt解密流程

1.前端发起请求,axios请求拦截器设置headers

service.interceptors.request.use(

config => {

// do something before request is sent

if (store.getters.token) {

// let each request carry token

// ['X-Token'] is a custom headers key

// please modify it according to the actual situation

config.headers['Authorization'] = getToken()

}

return config

},

error => {

// do something with request error

console.log(error) // for debug

return Promise.reject(error)

}

)

作者这里使用的是axios库配合拦截器,具体使用参考:https://www.jianshu.com/p/86122178002a

2.服务端解析headers中的token

const { Status, Code } = ctx.app.config

if (ctx.get('Authorization')) {

//拿出token

let token = ctx.get('Authorization');

try {

//解密token

ctx.app.jwt.verify(token, secret);

} catch (error) {

if (error.name == 'TokenExpiredError') {

//token过期啦

ctx.responseMsg(Status.FAIL.UNAUTHORIZED, { msg: Code.FAIL.TOKEN_EXPIRED.MSG });

return;

} else {

ctx.responseMsg(Status.FAIL.UNAUTHORIZED, { msg: Code.FAIL.TOKEN_EXPIRED.MSG });

return;

}

}

await next();

} else {

//不合法的请求

ctx.responseMsg(Status.FAIL.UNAUTHORIZED, { msg: Code.FAIL.ILLEGAL_TOKEN.MSG });

return;

}

token:请求头中获取到的token

secret:盐值,和加密的保持一致

其中关于jwt的解密工作使用了中间件,关于egg中间件参考:
https://eggjs.org/zh-cn/basics/middleware.html

3.服务端根据返回的约定code做出相应的响应

service.interceptors.response.use(

response => {

// if the custom code is not 20000, it is judged as an error.

const res = response.data;

if (res.code !== 20000) {

Message({

message: res.msg || 'Error',

type: 'error',

duration: 5 * 1000

})

} else {

return res

}

},

error => {

//console.log(error) // for debug

Message({

message: error.message,

type: 'error',

duration: 5 * 1000

})

if (error.response.status == 401) {

MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {

confirmButtonText: 'Re-Login',

cancelButtonText: 'Cancel',

type: 'warning'

}).then(() => {

store.dispatch('user/resetToken').then(() => {

location.reload()

})

})

} else if (error.response.status == 422) {

}

return Promise.reject(error)

}

)

其中的code是根据和后端人员约定规范的,可以参考restful风格:
https://zhuanlan.zhihu.com/p/66148320?utm_source=wechat_session&utm_medium=social&utm_oi=986957734650208256

如上即可实现基于jwt认证(第一次写,写得不好大佬们下手轻点)

以上是 【JS】基于jwt认证的实现 的全部内容, 来源链接: utcz.com/a/90905.html

回到顶部