业务场景

在前后分离场景下,越来越多的项目使用token作为接口的安全机制,APP端或者WEB端(使用VUE、REACTJS等构建)使用token与后端接口交互,以达到安全的目的。本文结合stackover以及本身项目实践,试图总结出一个通用的,可落地的方案。

基本思路

  • 单个token
  1. token(A)过期设置为15分钟
  2. 前端发起请求,后端验证token(A)是否过期;如果过期,前端发起刷新token请求,后端设置已再次授权标记为true,请求成功
  3. 前端发起请求,后端验证再次授权标记,如果已经再次授权,则拒绝刷新token的请求,请求成功
  4. 如果前端每隔72小时,必须重新登录,后端检查用户最后一次登录日期,如超过72小时,则拒绝刷新token的请求,请求失败
  • 授权token加上刷新token

用户仅登录一次,用户改变密码,则废除token,重新登录

1.0实现

1.登录成功,返回access_token和refresh_token,客户端缓存此两种token;
2.使用access_token请求接口资源,成功则调用成功;如果token超时,客户端
携带refresh_token调用中间件接口获取新的access_token;
3.中间件接受刷新token的请求后,检查refresh_token是否过期。
如过期,拒绝刷新,客户端收到该状态后,跳转到登录页;
如未过期,生成新的access_token和refresh_token并返回给客户端(如有可能,让旧的refresh_token失效),客户端携带新的access_token重新调用上面的资源接口。
4.客户端退出登录或修改密码后,调用中间件注销旧的token(使access_token和refresh_token失效),同时清空客户端的access_token和refresh_toke。

后端表
id user_id client_id client_secret refresh_token expire_in create_date del_flag

2.0实现

场景: access_token访问资源 refresh_token授权访问 设置固定时间X必须重新登录

1.登录成功,后台jwt生成access_token(jwt有效期30分钟)和refresh_token(jwt有效期15天),并缓存到redis(hash-key为token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token,也可以根据sub-key,废除部分设备的token。),设置过期时间为1个月,保证最终所有token都能删除),返回后,客户端缓存此两种token;
2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除);客户端再次携带refresh_token调用中间件接口获取新的access_token;
3.中间件接受刷新token的请求后,检查refresh_token是否过期。
如过期,拒绝刷新,删除refresh_token(废除); 客户端收到该状态后,跳转到登录页;
如未过期,检查缓存中是否有refresh_token(是否被废除),如果有,则生成新的access_token并返回给客户端,客户端接着携带新的access_token重新调用上面的资源接口。
4.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token和refresh_token(废除)),同时清空客户端侧的access_token和refresh_toke。
5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。
6.以上3刷新access_token可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:失效,长时间未登录,频繁刷新)

2.0 变动
1.登录
2.登录拦截器
3.增加刷新access_token接口
4.退出登录
5.修改密码

3.0实现

场景:自动续期 长时间未使用需重新登录

1.登录成功,后台jwt生成access_token(jwt有效期30分钟),并缓存到redis(hash-key为access_token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token),设置access_token过期时间为7天,保证最终所有token都能删除),返回后,客户端缓存此token;

2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的access_token,
再次请求接口资源。

3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清空客户端侧的access_token。

4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长时间未登录,频繁刷新)

5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

3.0 变动

1.登录
2.登录拦截器
3.退出登录
4.修改密码

1.3 场景:token过期重新登录 长时间未使用需重新登录

1.登录成功,后台jwt生成access_token(jwt有效期7天),并缓存到redis,key为 "user_id:access_token",value为access_token(根据用户id,可以人工废除指定用户全部token),设置缓存过期时间为7天,保证最终所有token都能删除,请求返回后,客户端缓存此access_token;

2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的access_token,
再次请求接口资源。

3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清空客户端侧的access_token。

4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长时间未登录,频繁刷新)

5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

1.3 变动

1.登录
2.登录拦截器
3.退出登录
4.修改密码

解决方案

2.0 场景: access_token访问资源 refresh_token授权访问 设置固定时间X必须重新登录

1.登录成功,后台jwt生成access_token(jwt有效期30分钟)和refresh_token(jwt有效期15天),并缓

存到redis(hash-key为token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全

部token,也可以根据sub-key,废除部分设备的token。),设置过期时间为1个月,保证最终所有token都

能删除),返回后,客户端缓存此两种token;

2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

token超时,中间件删除access_token(废除);客户端再次携带refresh_token调用中间件接口获取新的

access_token;

3.中间件接受刷新token的请求后,检查refresh_token是否过期。

如过期,拒绝刷新,删除refresh_token(废除); 客户端收到该状态后,跳转到登录页;

如未过期,检查缓存中是否有refresh_token(是否被废除),如果有,则生成新的access_token并返回给

客户端,客户端接着携带新的access_token重新调用上面的资源接口。

4.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token和refresh_token(

废除)),同时清空客户端侧的access_token和refresh_toke。

5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

6.以上3刷新access_token可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(

拒绝的场景:失效,长时间未登录,频繁刷新)

2.0 变动

1.登录

2.登录拦截器

3.增加刷新access_token接口

4.退出登录

5.修改密码

3.0 场景:自动续期 长时间未使用需重新登录

1.登录成功,后台jwt生成access_token(jwt有效期30分钟),并缓存到redis(hash-key为

access_token,sub-key为手机号,value为设备唯一编号(根据手机号码,可以人工废除全部token,也可以

根据sub-key,废除部分设备的token。),设置access_token过期时间为1个月,保证最终所有token都能删

除),返回后,客户端缓存此token;

2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的

access_token,

再次请求接口资源。

3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清

空客户端侧的access_token。

4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长

时间未登录,频繁刷新)

5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

3.0 变动

1.登录

2.登录拦截器

3.退出登录

4.修改密码

4.0 场景:token过期重新登录 长时间未使用需重新登录

1.登录成功,后台jwt生成access_token(jwt有效期7天),并缓存到redis,key为

"user_id:access_token" + 用户id,value为access_token(根据用户id,可以人工废除指定用户全部

token),设置缓存过期时间为7天,保证最终所有token都能删除,请求返回后,客户端缓存此

access_token;

2.使用access_token请求接口资源,校验成功且redis中存在该access_token(未废除)则调用成功;如果

token超时,中间件删除access_token(废除),同时生成新的access_token并返回。客户端收到新的

access_token,

再次请求接口资源。

3.客户端退出登录或修改密码后,调用中间件注销旧的token(中间件删除access_token(废除)),同时清

空客户端侧的access_token。

4.以上2 可以增加根据登录时间判断最长X时间必须重新登录,此时则拒绝刷新token。(拒绝的场景:长

时间未登录,频繁刷新)

5.如手机丢失,可以根据手机号人工废除指定用户设备关联的token。

4.0 变动

1.登录

2.登录拦截器

3.退出登录

4.修改密码

最终实现

后端

  1. 在登录接口中 如果校验账号密码成功 则根据用户id和用户类型创建jwt token(有效期设置为-1,即永不过期),得到A
  2. 更新登录日期(当前时间new Date()即可)(业务上可选),得到B
  3. 在redis中缓存key为ACCESS_TOKEN:userId:A(加上A是为了防止用户多个客户端登录 造成token覆盖),value为B的毫秒数(转换成字符串类型),过期时间为7天(7 * 24 * 60 * 60)
  4. 在登录结果中返回json格式为{"result":"success","token": A}
  5. 用户在接口请求header中携带token进行登录,后端在所有接口前置拦截器进行拦截,作用是解析token 拿到userId和用户类型(用户调用业务接口只需要传token即可), 如果解析失败(抛出SignatureException),则返回json(code = 0 ,info= Token验证不通过, errorCode = '1001'); 此外如果解析成功,验证redis中key为ACCESS_TOKEN:userId:A 是否存在 如果不存在 则返回json(code = 0 ,info= 会话过期请重新登录, errorCode = '1002'); 如果缓存key存在,则自动续7天超时时间(value不变),实现频繁登录用户免登陆。
  6. 把userId和用户类型放入request参数中 接口方法中可以直接拿到登录用户信息
  7. 如果是修改密码或退出登录 则废除access_tokens(删除key)

前端(VUE)

    1. 用户登录成功,则把username存入cookie中,key为loginUser;把token存入cookie中,key为accessToken 把token存入Vuex全局状态中
    2. 进入首页

文章摘自 花间_拾零的个人空间https://my.oschina.net/odetteisgorgeous/blog/1920762

JWT生成token及过期处理方案的更多相关文章

  1. 国服最强JWT生成Token做登录校验讲解,看完保证你学会!

    转载于:https://blog.csdn.net/u011277123/article/details/78918390 Free码农 2017-12-28 00:08:02 JWT简介 JWT(j ...

  2. 利用jwt生成token,用于http请求身份验证

    前段时间在做移动端接口过程中,考虑到安全性,所有移动端发送请求(除了登录请求)过程中进行token有效验证. 1.利用jwt生成token a.导入jwt相关包 <!-- jwt --> ...

  3. 使用 JWT 生成 Token 代码示例

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

  4. Token_使用JWT生成token

    1.token三部分 header   { "typ": "JWT", "alg": "HS256"   } paylo ...

  5. tp5使用jwt生成token,做api的用户认证

    首先 composer 安装  firebase/php-jwt github:https://github.com/firebase/php-jwt composer require firebas ...

  6. JWT生成token

    1.JWT简介 JSON Web Token 简称JWT.一个JWT实际上就是一个字符串,它由三部分组成,头部.载荷与签名.JWT生成的token是这样的 2.Json Web Token(JWT)生 ...

  7. .NET6 JWT(生成Token令牌)

    一.Net 6环境下的.net core项目里如何使用JWT. 第一步,在Nuget引入JWT.Microsoft.AspNetCore.Authentication.JwtBearer这两个NuGe ...

  8. JWT生成Token做登录校验

    一.JWT的优点 1.服务端不需要保存传统会话信息,没有跨域传输问题,减小服务器开销. 2.jwt构成简单,占用很少的字节,便于传输. 3.json格式通用,不同语言之间都可以使用. 二.使用JWT进 ...

  9. JSON Web Token (JWT)生成Token及解密实战。

    昨天讲解了JWT的介绍.应用场景.优点及注意事项等,今天来个JWT具体的使用实践吧. 从JWT官网支持的类库来看,jjwt是Java支持的算法中最全的,推荐使用,网址如下. https://githu ...

随机推荐

  1. c# 通过win32 api 得到指定Console application Content

    已知的问题: 1. 调试的时候会报IO 异常,非调试环境是正常的 2. Windows 应用程序才可以使用,可以用非windows应用程序包一层 using System; using System. ...

  2. getBrandWCPayRequest 和 chooseWXPay 的区别

    getBrandWCPayRequest 和 chooseWXPay 都是发起微信支付请求,chooseWXPay 依赖 http://res.wx.qq.com/open/js/jweixin-1. ...

  3. Cassandra开发入门文档第二部分(timeuuid类型、复合主键、静态字段详解)

    timeuuid类型 timeuuid具有唯一索引和日期时间的综合特性,可以与日期和时间函数联合使用,常用的关联函数: dateOf() now() minTimeuuid() and maxTime ...

  4. Operation之变换操作符

    buffer buffer方法的作用是缓冲组合, 第一个参数是缓冲时间, 第二个参数是缓冲个数, 第三个参数是线程 该方法简单来说就是缓存Observable中发出的新元素, 当元素达到某个数量, 或 ...

  5. traefik安装

    注意这篇文档有个错误,需要改正一下: 1.nginx1-7.yaml nginx1-8.yaml traefik.yaml 这三个文件里面的80端口需要改成8080端口,否则报错,其他的文件不变. 2 ...

  6. Centos7安装文件传输软件rz sz

    一直使用Xshell的xftp传输文件,谁知道忽然无法正常使用. 于是,决定用户rz进行传输 安装步骤也比较简单 1.首先安装第三方源(以下源比默认源包含更多安装包,建议添加该源使用) yum ins ...

  7. notepad++之个性化配置

    在Linux下,喜欢用vi做文件编辑(vim反倒没怎么用).在Windows系统下,用得最多的则是notepad++.开源大法好.. 之所以选择notepad++,是因为其不会强制你命名并保存文件,你 ...

  8. prototype和__proto__的关系是什么?

    我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法.(这个对象下面有个属性,这个属性是另外一个对象的应用 ,这个属性就 ...

  9. activiti学习4:流程文件的部署

    activiti学习4:流程文件的部署 用bpmn规范定义好一个流程得到流程定义文件后,需要把该文件部署到activiti的数据库后,这个流程才可以使用. activiti中和流程定义相关的操作都需要 ...

  10. Ubuntu下重启mysql

    启动mysql: 方式一:sudo /etc/init.d/mysql start 方式二:sudo service mysql start 停止mysql: 方式一:sudo /etc/init.d ...