写点什么

登录验证那些事儿

发布于: 1 小时前
登录验证那些事儿

前言

在以前的项目我们一般使用 session 或者 cookie 来存储已登录的用户信息,这样到达一个免除重复登录的问题,那么如何登录,又如何验证,就是一直在讨论的问题。今天我们对这些技术点进行一个梳理。



一、什么是认证(Authentication)


(比如:你每天上下班打卡,都需要通过指纹打卡,当你的指纹和系统里录入的指纹相匹配时,就打卡成功。)


互联网中的认证:


  • 用户名密码登录

  • 邮箱发送登录链接

  • 手机号接收验证码

  • 邮箱/验证码,你就是账号的主人

二、什么是授权(Authorization)


  • 比如手机安装 APP 的时候,会询问是否允许授予权限(访问相册、位置等权限)

  • 比如在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)

  • 比如网站登录的时候,可以使用 QQ,微信进行登录。(访问你的个人资料,好友信息等)


实现授权的方式有:cookie、session、token、OAuth 等

三、什么是凭证(Credentials)


  • 比如生活中,每个人都会有一张专属的居民身份证,是用于证明持有人身份的一种法定证件。

  • 通过身份证,我们可以办理手机卡/银行卡/个人贷款等等,这就是认证的凭证。

四、怎么让浏览器记住我是谁?


HTTP 是无状态的协议(就是说,它对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。


所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我?),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器,而这个状态需要 ==通过 cookie 或者 session 去实现==。

五、什么是 Cookie


  • cookie 存储在客户端(本机的缓存文件夹中):cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。

  • cookie 是不可跨域的:每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain,指的是所属域名,一般指当前域名)。

5.1.使用 cookie 时需要考虑的问题

  • 因为存储在客户端,容易被客户端篡改,使用前需要验证合法性

  • 不要存储敏感数据,比如用户密码,账户余额

  • 使用 httpOnly 在一定程度上提高安全性

  • 尽量减少 cookie 的体积,能存储的数据量不能超过 4kb

  • 设置正确的 domain 和 path,减少数据传输

  • cookie 无法跨域

  • 一个浏览器针对一个网站最多存 20 个 Cookie,浏览器一般只允许存放 300 个 Cookie

  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

六、什么是 Session


  • session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的 cookie 中


请求图示:



因为 session 在 BS 架构中最常用,就讲多一点。

6.1.session 认证流程:

  1. 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session。

  2. 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器。

  3. 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名。

  4. 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。


根据以上流程可知,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。

6.2.使用 session 时需要考虑的问题

  • 将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session

  • 当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。

  • 当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。

  • sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办?一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现

  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

6.3.Cookie 和 Session 的区别

  • 安全性不同:Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。

  • 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。

  • 有效期不同:Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。

  • 存储大小不同:单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源,因此选用 cookie 还是 session 技术,更多取决于你自身系统的需求。

七、什么是 Token(令牌)

如今,微服务架构盛行,除去传统的 cookie 和 session 技术,还多一个 Acesss Token 令牌技术。

7.1.全称叫 Acesss Token


  • 一般 token 的组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)。

  • 特点:- 服务端无状态化、可扩展性好- 支持移动端设备- 安全- 支持跨程序调用,就是不受域名限制。


使用场景:


一般网站就是,当用户登录成功后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌,就可以使用系统了。

7.2.token 的身份验证流程:


流程如下:


  1. 客户端使用用户名跟密码进行登录。

  2. 服务端收到请求,去验证用户名与密码。

  3. 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端。

  4. 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里。

  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 token。

  6. 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据。


服务端生成:



客户端保存:每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里。



Token 是无状态协议中认证用户的一种形式,相比于传统的 cookie,不受域名限制。

7.3.使用 token 时需要考虑的问题

  • 如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis。

  • token 完全由应用管理,所以它可以避开同源策略

  • token 可以避免 CSRF 攻击(因为不需要 cookie 了)

  • 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

八、什么是 Refresh Token

作为后端开发人员,是否有过这种经历,在使用接口测试的时候,往往要求填写 token 信息,然而这 token 需要运行前端项目,然后登陆,然后生成一个 token,然后把这个 token 放到我们的接口调试器中, 再模拟发出请求。而且 token 设有有效期,隔三差五重新登录,总之,你要想测试你的后端接口,还需要跑前端项目,很麻烦有木有?于是就有了 refresh token。

8.1.refresh token


如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,会很麻烦。有了 refresh token,可以减少这个麻烦,当前 token 过了有效期以后,就在客户端中直接用 refresh token 去更新 access token,获得新的 token,然后就可以愉快的玩耍了,无需用户再登录之类的额外操作。


特点:


  1. Access Token 的有效期比较短,当 Acesss Token 由于过期而失效时,使用 Refresh Token 就可以获取到新的 Token,如果 Refresh Token 也失效了,用户就只能重新登录了。

  2. Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求。

8.2.Token 和 Session 的区别

  • Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。

  • 而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。

  • 一个系统中同时拥有 Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重发攻击,而 Session 就必须依赖链路层来保障通讯安全。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。


多说一句:Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。


而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是 认证 和 授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的。不可以转移到其它 App 上,也不可以转到其它用户上。


所以简单来说:


九、什么是 JWT


  • JSON Web Token(简称 JWT)是目前最流行的==跨域认证==解决方案。

  • 是一种认证授权机制。

  • JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)。


  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
复制代码


  • JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。

  • 可以使用 HMAC 算法或者是 RSA 的公/私秘钥对 JWT 进行签名。因为数字签名的存在,这些传递的信息是可信的。

9.1.JWT 的原理

9.2.JWT 认证流程:

  1. 用户输入用户名/密码登录,服务端认证成功后,会返回给客户端一个 JWT 字符串。

  2. 客户端将 这个 jwt 格式的 token 字符串保存到本地(通常使用 localstorage,也可以使用 cookie)。

  3. 当用户希望访问一个受保护的路由或者资源的时候,需要请求头的 Authorization 字段中使用 Bearer 模式添加 JWT。

  4. 因为 JWT 并不使用 Cookie 的,所以你可以使用任何域名提供你的 API 服务而不需要担心跨域资源共享问题(CORS)。

  5. 因为用户的状态不再存储在服务端的内存中,所以这是一种无状态的认证机制

9.3.使用 JWT 时需要考虑的问题

  • 因为 JWT 并不依赖 Cookie 的,所以你可以使用任何域名提供你的 API 服务而不需要担心跨域资源共享问题(CORS)

  • JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。

  • JWT 不加密的情况下,不能将秘密数据写入 JWT。

  • JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。

  • JWT 最大的优势是服务器不再需要存储 Session,使得服务器认证鉴权业务可以方便扩展。但这也是 JWT 最大的缺点:由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑。

  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

  • JWT 适合一次性的命令认证,颁发一个有效期极短的 JWT,即使暴露了危险也很小,由于每次操作都会生成新的 JWT,因此也没必要保存 JWT,真正实现无状态。

  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

9.4.Token 和 JWT 的区别

相同:


  • 都是访问资源的令牌

  • 都可以记录用户的信息

  • 都是使服务端无状态化

  • 都是只有验证成功后,客户端才能访问服务端上受保护的资源


区别:


  • Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。

  • JWT:将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。


token 可以是一个短字符串,如下


25d9048a-dacb-45c3-ac0c-28be4340c8c1
复制代码


JWT 通常是一个长字符串,以点分割三段,如下


eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1OTMzMDkyNDUsInVzZXJuYW1lIjoiYWRtaW4ifQ.BjiEVjhapNvJTTpRFrWFN8_-Ng9YLo14XcHv3h1dcoA
复制代码


可以看出都是一些加密的字符串。顺便提一下加密问题。


在很久以前,常用的是这样 MD5、AES、Base64算法数据加密


现在基本上都是推荐使用哈希算法来加密。

十、使用加密算法时需要考虑的问题


  • 永远使用 哈希算法 来处理密码,绝不要使用 Base64 或其他编码方式来存储密码,这和以明文存储密码是一样的,使用哈希,而不要使用编码。因为编码以及加密,都是双向的过程,而密码是保密的,应该只被它的所有者知道, 这个过程必须是单向的。哈希正是用于做这个的,从来没有解哈希这种说法, 但是编码就存在解码,加密就存在解密。

  • 绝不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用强密码哈希算法。

  • 绝不要以明文形式显示或发送密码,即使是对密码的所有者也应该这样。


目前常见的前后端鉴权方式


  • Session-Cookie

  • Token 验证(包括 JWT,SSO)

  • OAuth2.0(开放授权)


<hr>


本文梳理了一些理论知识点,多少有失偏颇,下一篇为实战。拜拜~



发布于: 1 小时前阅读数: 5
用户头像

万水千山总是情,点个关注行不行。 2020.04.17 加入

烟水茫茫,千里斜阳暮。 山无数,乱红如雨,不记来时路。

评论

发布
暂无评论
登录验证那些事儿