登录认证几乎是任何一个系统的标配,web 系统、APP、PC 客户端等,好多都需要注册、登录、授权认证。
登录是每个网站中都经常用到的一个功能,在页面上我们输入账号密码,敲一下回车键,就登录了,但这背后的登录原理你是否清楚呢?今天我们就来介绍几种常用的登录方式。
Cookie + Session 登录
Token 登录
SSO 单点登录
OAuth 第三方登录
HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password, 简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的 风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth
Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效
OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
更适用CDN:可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
去耦:不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
性能:一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET,Ruby,Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).
以一个电商系统,假设淘宝为例,如果我们想要下单,首先需要注册一个账号。拥有了账号之后,我们需要输入用户名(比如手机号或邮箱)、密码完成登录过程。之后如果你在一段时间内再次进入系统,是不需要输入用户名和密码的,只有在连续长时间不登录的情况下(例如一个月没登录过)访问系统,再次需要输入用户名和密码。如果使用频率很频繁,通常是一年都不用再输一次密码,所以经常在换了一台电脑或者一部手机之后,一些经常使用的网站或 APP 不记得密码了。
提炼出来整个过程大概就是如下几步:
首次使用,需要通过邮箱或手机号注册;
注册完成后,需要提供用户名和密码完成登录;
下次再使用,通常不会再次输入用户名和密码即可直接进入系统并使用其功能(除非连续长时间未使用);
OAuth 认证比较常见的就是微信登录、微博登录、qq登录等,简单来说就是利用这些比较权威的网站或应用开放的 API 来实现用户登录,用户可以不用在你的网站或应用上注册账号,直接用已有的微信、微博、qq 等账号登录。
这一样一来,即省了用户注册的时间,又简化了你的系统的账号体系。从而既可以提高用户注册率可以节省开发时间,同时,安全性也有了保障。
维基百科对它的解释摘要如下:
OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。
假设我们开发了一个电商平台,并集成了微信登录,以这个场景为例,说一下 OAuth 的工作原理。
讲之前需要了解其中涉及到的几个角色:
用户:即使用我们平台的用户
用户终端:即最终用户使用的 APP 端或 web 端
应用服务器端:即我们的服务器端
授权服务器端:这里就是微信处理授权请求的服务器
好的,接下来开始在我们的电商平台web端实现微信登录功能。微信网页授权是授权码模式(authorization code)的 OAuth 授权模式。
我们电商平台的用户过来登录,常用场景是点击“微信登录”按钮;
接下来,用户终端将用户引导到微信授权页面;
用户同意授权,应用服务器重定向到之前设置好的 redirect_uri (应用服务器所在的地址),并附带上授权码(code);
应用服务器用上一步获取的 code 向微信授权服务器发送请求,获取 access_token,也就是上面说的令牌;
之后应用服务器用上一步获取的 access_token 去请求微信授权服务器获取用户的基本信息,例如头像、昵称等;
早期互联网以 web 为主,客户端是浏览器,所以 Cookie-Session 方式最那时候最常用的方式,直到现在,一些 web 网站依然用这种方式做认证。
认证过程大致如下:
用户输入用户名、密码或者用短信验证码方式登录系统;
服务端验证后,创建一个 Session 信息,并且将 SessionID 存到 cookie,发送回浏览器;
下次客户端再发起请求,自动带上 cookie 信息,服务端通过 cookie 获取 Session 信息进行校验;
弊端
只能在 web 场景下使用,如果是 APP 中,不能使用 cookie 的情况下就不能用了;
即使能在 web 场景下使用,也要考虑跨域问题,因为 cookie 不能跨域;
cookie 存在 CSRF(跨站请求伪造)的风险;
如果是分布式服务,需要考虑 Session 同步问题;
由于传统的 Cookie-Session 认证存在诸多问题,可以把上面的方案改造一下。改动的地方如下:
不用 cookie 做客户端存储,改用其他方式,web 下使用 local storage,APP 中使用客户端数据库,这样就实现了跨域,并且避免了 CSRF ;
服务端也不存 Session 了,把 Session 信息拿出来存到 Redis 等内存数据库中,这样即提高了速度,又避免了 Session 同步问题;
经过改造之后变成了如下的认证过程:
用户输入用户名、密码或者用短信验证码方式登录系统;
服务端经过验证,将认证信息构造好的数据结构存储到 Redis 中,并将 key 值返回给客户端;
客户端拿到返回的 key,存储到 local storage 或本地数据库;
下次客户端再次请求,把 key 值附加到 header 或者 请求体中;
服务端根据获取的 key,到 Redis 中获取认证信息;
上面的方案虽然经过了改版,但还是需要客户端和服务器端维持一个状态信息,比如用 cookie 换 session ,或者用 key 换 Redis 的 value 信息,基于 JWT 的 Token 认证方案可以省去这个过程。
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
认证过程
依然是用户登录系统;
服务端验证,将认证信息通过指定的算法(例如HS256)进行加密,例如对用户名和用户所属角色进行加密,加密私钥是保存在服务器端的,将加密后的结果发送给客户端,加密的字符串格式为三个'.' 分隔的字符串 Token,分别对应头部、载荷与签名,头部和载荷都可以通过 base64 解码出来,签名部分不可以;
客户端拿到返回的 Token,存储到 local storage 或本地数据库;
下次客户端再次发起请求,将 Token 附加到 header 中;
服务端获取 header 中的 Token ,通过相同的算法对 Token 中的用户名和所属角色进行相同的加密验证,如果验证结果相同,则说明这个请求是正常的,没有被篡改。这个过程可以完全不涉及到查询 Redis 或其他存储;
优点
使用 json 作为数据传输,有广泛的通用型,并且体积小,便于传输;
不需要在服务器端保存相关信息;
jwt 载荷部分可以存储业务相关的信息(非敏感的),例如用户信息、角色等;
参考信息:
OAuth: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
JWT:https://jwt.io/introduction/
http://blog.leapoahead.com/2015/09/06/understanding-jwt/
JWT Java 库: https://github.com/jwtk/jjwt
扫描二维码
获取更多精彩
小帅搜
而这些并不是完全重要,更加重要的问题是, 我们都知道,只要有意义,那么就必须慎重考虑。生活中,若一个工具箱出现了,我们就不得不考虑它出现了的事实。一个工具箱,发生了会如何,不发生又会如何。这种事实对本人来说意义重大,相信对这个世界也是有一定意义的。总结的来说, 我认为, 带着这些问题,我们来审视一下一个工具箱。而这些并不是完全重要,更加重要的问题是, 既然如此, 那么, 现在,解决一个工具箱的问题,是非常非常重要的。所以, 总结的来说, 在这种困难的抉择下,本人思来想去,寝食难安。海贝尔曾经说过,人生就是学校。在那里,与其说好的教师是幸福,不如说好的教师是不幸。这句话语虽然很短,但令我浮想联翩。带着这些问题,我们来审视一下一个工具箱。贝多芬在不经意间这样说过,卓越的人一大优点是:在不利与艰难的遭遇里百折不饶。我希望诸位也能好好地体会这句话。一个工具箱因何而发生?。
总结的来说, 我认为, 问题的关键究竟为何? 一般来讲,我们都必须务必慎重的考虑考虑。现在,解决一个工具箱的问题,是非常非常重要的。所以, 问题的关键究竟为何? 一个工具箱的发生,到底需要如何做到,不一个工具箱的发生,又会如何产生。一个工具箱因何而发生?叔本华在不经意间这样说过,意志是一个强壮的盲人,倚靠在明眼的跛子肩上。带着这句话,我们还要更加慎重的审视这个问题:一个工具箱因何而发生?生活中,若一个工具箱出现了,我们就不得不考虑它出现了的事实。我们一般认为,抓住了问题的关键,其他一切则会迎刃而解。而这些并不是完全重要,更加重要的问题是, 生活中,若一个工具箱出现了,我们就不得不考虑它出现了的事实。我们都知道,只要有意义,那么就必须慎重考虑。一个工具箱的发生,到底需要如何做到,不一个工具箱的发生,又会如何产生。在这种困难的抉择下,本人思来想去,寝食难安。一个工具箱因何而发生?我认为, 一般来讲,我们都必须务必慎重的考虑考虑。笛卡儿曾经说过,读一切好书,就是和许多高尚的人谈话。我希望诸位也能好好地体会这句话。歌德在不经意间这样说过,没有人事先了解自己到底有多大的力量,直到他试过以后才知道。这句话语虽然很短,但令我浮想联翩。在这种困难的抉择下,本人思来想去,寝食难安。每个人都不得不面对这些问题。在面对这种问题时, 既然如此, 每个人都不得不面对这些问题。在面对这种问题时, 我认为, 问题的关键究竟为何? 就我个人来说,一个工具箱对我的意义,不能不说非常重大。我认为, 一个工具箱的发生,到底需要如何做到,不一个工具箱的发生,又会如何产生。佚名在不经意间这样说过,感激每一个新的挑战,因为它会锻造你的意志和品格。我希望诸位也能好好地体会这句话。伏尔泰曾经说过,不经巨大的困难,不会有伟大的事业。带着这句话,我们还要更加慎重的审视这个问题:经过上述讨论总结的来说, 带着这些问题,我们来审视一下一个工具箱。一个工具箱,到底应该如何实现。经过上述讨论既然如何, 总结的来说。
联系客服