token登录验证&谷歌二次验证

http是无状态的,那么应该如何记住登录状态呢?
以前的做法是在客户端cookie中保存sessionId,服务器端的session中保存sessionId,每次客户端发送请求的时候都带上sessionId,在服务端进行验证。
现在前后端分离,由于服务器之间不能共享内存,因此服务器之间session不能互通,因此不能使用session去存储用户的登录信息,一般使用token方式去记录登陆状态。区别就是token使用Redis缓存去存储这个用户标识。
token进行登录验证的步骤如下
1. 客户端输入用户名和密码向服务端发起验证
2. 服务端验证通过之后根据某种规则声称用户的token并返回,这个token保存在redis中,保证不同服务器间共享
3. 客户端存储该token,可以存储在sessionStorage或者cookie中
4. 后续服务器的每次请求都在请求头携带token发送到服务端
5. 服务端在执行方法前先对请求进行验证,取出token查询redis中有没有对应的值
前端使用的技术
以vue.js前端框架为例,用到的关键技术有路由导航守卫和拦截器
路由导航守卫主要是保证没有获得token时不能访问除登录外的其他页面,这里不对token进行验证,只是判断token存不存在,拦截器主要目的是让请求头携带token
//路由导航守卫控制访问权限
//为路由对象,添加beforeEach 导航守卫
router.beforeEach((to, from, next) => {
if(to.path === '/login') return next()
const tokenStr = window.sessionStorage.getItem('token')
if(!tokenStr) return next('/login')
next()
})
//退出功能
//基于token的方式实现退出只需要销毁本地的token即可
window.sessionStorage.clear()
this.$router.push('/login')
//通过axios请求拦截器添加token,保证拥有获取数据的权限
axios.interceptors.request.use(config => {
config.headers.Authorization = window.sessisonStorage.getItem('token');
return config;
})
JWT(JSON WEB TOKEN)
jwt的构成分为三部分:
第一部分头部(header):两部分信息:
- 声明类型
- 声明加密的算法 通常直接使用HMAC SHA256
完整的头部就像下面这样的JSON
{
'typ': 'JWT',
'alg': 'HS256'
}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分
第二部分(payload),存放有效信息,包含三个部分:
- 标准中注册的声明
- 公共的声明
- 私有的声明
第三部分(signature),签证信息,由三个部分组成:
- header(base64后的)
- payload(base64后的)
- secret
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
如何应用jwt
一般是在请求头里加入Authorization,并加上Bearer标注:
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer' + token
}
})
有点:
- 因为json的通用性,所以jwt是可以进行跨语言支持的,像java,javascript,nodejs,php等很多语言都可以使用
- 因为有了payload部分,所以jwt可以再自身存储一些其他业务啥逻辑所需要的非敏感信息
- 不需要在服务端保存会话信息,所以它易于应用的扩展
项目中使用到的二次验证
两步验证已经被广泛应用于各种互联网应用当中,用来提供安全性。
对于如何使用两步验证,大家并不陌生,无非是开启两步验证,然后出现一个二维码,使用支持两步验证的移动应用比如 Google Authenticator 或者 LassPass Authenticator 扫一下二维码。
这时候应用会出现一个 6 位数的一次性密码,首次需要输入验证从而完成开启过程。
以后在登陆的时候,除了输入用户名和密码外,还需要把当前的移动应用上显示的 6 位数编码输入才能完成登陆。