写点什么

Java 中高级核心知识全面解析 (2),腾讯 Java 面试

发布于: 1 小时前

那为什么 token 不会存在这种问题呢?


我是这样理解的:一般情况下我们使用 JWT 的话,在我们登录成功获得 token 之后,一般会选择存放在 local storage 中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 token,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 token 的,所以这个请求将是非法的。


但是这样会存在 XSS 攻击中被盗的风险,为了避免 XSS 攻击,你可以选择将 token 存储在标记为 httpOnly 的 cookie 中。但是,这样又导致了你必须自己提供 CSRF 保护。


具体采用上面哪两种方式存储 token 呢,大部分情况下存放在 local storage 下都是最好的选择,某些情况下可能需要存放在标记为 httpOnlycookie 中会更好。

3.适合移动端应用

使用 Session 进行身份认证的话,需要保存一份信息在服务器端,而且这种方式会依赖到 Cookie(需要 Cookie 保存 SessionId),所以不适合移动端。


但是,使用 token 进行身份认证就不会存在这种问题,因为只要 token 可以被客户端存储就能够使用,而且 token 还可以跨语言使用。

4.单点登录友好

使用 Session 进行身份认证的话,实现单点登录,需要我们把用户的 Session 信息保存在一台电脑上,并且还会遇到常见的 Cookie 跨域的问题。但是,使用 token 进行认证的话, token 被保存在客户端,不会存在这些问题。

二、Token 认证常见问题以及解决办法

1.注销登录等场景下 token 还有效

与之类似的具体相关场景有:


  1. 退出登录;

  2. 修改密码;

  3. 服务端修改了某个用户具有的权限或者角色;

  4. 用户的帐户被删除/暂停。

  5. 用户由管理员注销;


这个问题不存在于 Session 认证方式中,因为在 Session 认证方式中,遇到这种情况的话服务端删除对应的 Session 记录即可。但是,使用 token 认证的方式就不好解决了。我们也说过了,token 一旦派发出去,如果后端不增加其他逻辑的话,它在失效之前都是有效的。那么,我们如何解决这个问题呢?查阅了很多资料,总结了下面几种方案:


  • 将 token 存入内存数据库:将 token 存入 DB 中,redis 内存数据库在这里是是不错的选择。如果需要让某个 token 失效就直接从 redis 中删除这个 token 即可。但是,这样会导致每次使用 token 发送请求都要先从 DB 中查询 token 是否存在的步骤,而且违背了 JWT 的无状态原则。

  • 黑名单机制:和上面的方式类似,使用内存数据库比如 redis 维护一个黑名单,如果想让某个 token 失效的话就直接将这个 token 加入到 黑名单 即可。然后,每次使用 token 进行请求的话都会先判断这个 token 是否存在于黑名单中。

  • 修改密钥 (Secret) : 我们为每个用户都创建一个专属密钥,如果我们想让某个 token 失效,我们直接修改对应用户的密钥即可。但是,这样相比于前两种引入内存数据库带来了危害更大,比如:1.**如果服务是分布式的,则每次发出新的 token 时都必须在多台机器同步密钥。为此,你需要将必须将机密存储在数据库或其他外部服务中,这样和 Session 认证就没太大区别了。**2.如果用户同时在两个浏览器打开系统,或者在手机端也打开了系统,如果它从一个地方将账号退出,那么其他地方都要重新进行登录,这是不可取的。

  • 保持令牌的有效期限短并经常轮换 :很简单的一种方式。但是,会导致用户登录状态不会被持久记录,而且需要用户经常登录。

2.token 的续签问题

token 有效期一般都建议设置的不太长,那么 token 过期后如何认证,如何实现动态刷新 token,避免用户经常需要重新登录?


我们先来看看在 Session 认证中一般的做法:假如 session 的有效期 30 分钟,如果 30 分钟内用户有访问,就把 session 有效期被延长 30 分钟


  1. 类似于 Session 认证中的做法:这种方案满足于大部分场景。假设服务端给的 token 有效期设置为 30 分钟,服务端每次进行校验时,如果发现 token 的有效期马上快过期了,服务端就重新生成 token 给客户端。客户端每次请求都检查新旧 token,如果不一致,则更新本地的 token。这种做法的问题是仅仅在快过期的时候请求才会更新 token ,对客户端不是很友好。

  2. 每次请求都返回新 token :这种方案的的思路很简单,但是,很明显,开销会比较大。

  3. token 有效期设置到半夜 :这种方案是一种折衷的方案,保证了大部分用户白天可以正常登录,适用于对安全性要求不高的系统。

  4. 用户登录返回两个 token :第一个是 acessToken ,它的过期时间 token 本身的过期时间比如半个小时,另外一个是 refreshToken 它的过期时间更长一点比如为 1 天。客户端登录后,将 accessToken 和 refreshToken 保存在本地,每次访问将 accessToken 传给服务端。服务端校验 accessToken 的有效性,如果过期的话,就将 refreshToken 传给服务端。如果有效,服务端就生成新的 accessToken 给客户端。否则,客户端就重新登录即可。该方案的不足是:1.需要客户端来配合;2.用户注销的时候需要同时保证两个 token 都无效;3.重新请求获取 token 的过程中会有短暂 token 不可用的情况(可以通过在客户端设置定时器,当accessToken 快过期的时候,提前去通过 refreshToken 获取新的accessToken)。

文末 java 面试题,进阶技术大纲,架构资料分享

我将这三次阿里面试的题目全部分专题整理出来,并附带上详细的答案解析,生成了一份 PDF 文档,有兴趣的朋友们可以点击这里即可免费领取


  • 第一个要分享给大家的就是算法和数据结构



  • 第二个就是数据库的高频知识点与性能优化



  • 第三个则是并发编程(72 个知识点学习)



  • 最后一个是各大 JAVA 架构专题的面试点+解析+我的一些学习的书籍资料



还有更多的 Redis、MySQL、JVM、Kafka、微服务、Spring 全家桶等学习笔记这里就不一一列举出来

用户头像

VX:Lzzzzzz63 领取资料 2021.07.07 加入

还未添加个人简介

评论

发布
暂无评论
Java中高级核心知识全面解析(2),腾讯Java面试