前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【小家思想】通俗易懂版讲解JWT和OAuth2,以及他俩的区别和联系(Token鉴权解决方案)

【小家思想】通俗易懂版讲解JWT和OAuth2,以及他俩的区别和联系(Token鉴权解决方案)

作者头像
YourBatman
发布2019-09-03 15:13:14
9.2K0
发布2019-09-03 15:13:14
举报
文章被收录于专栏:BAT的乌托邦BAT的乌托邦
什么是OAuth

OAuth是一个关于授权(authorization)的开放网络协议,在全世界得到广泛应用,目前的版本是2.0版。

OAuth是一种安全的授权框架,提供了一套详细的授权机制。用户或应用可以通过公开的或私有的设置,授权第三方应用访问特定资源。它详细描述了系统中不同角色、用户、服务前端应用(比如API),以及客户端(比如网站或移动App)之间怎么实现相互认证。

Oauth2定义了一组相当复杂的规范。涉及到:Roles角色、Client Types客户端类型、Client Profile客户端描述、Authorization Grants认证授权、Endpoints终端等。

OAuth2.0中最经典最常用的一种授权模式:授权码模式。此模式和JWT标准特别像

关于OAuth更详尽的了解,请参考阮一峰老师的一篇文章:理解OAuth 2.0

什么是JWT

提供了一种用于发布接入令牌(Access Token),并对发布的签名接入令牌进行验证的方法。 令牌(Token)本身包含了一系列声明,应用程序可以根据这些声明限制用户对资源的访问。

JWT是一种安全标准。基本思路就是用户提供用户名和密码给认证服务器,服务器验证用户提交信息信息的合法性;如果验证成功,会产生并返回一个Token(令牌),用户可以使用这个token访问服务器上受保护的资源。

详解JWT

Json web token(JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

基于session认证所显露的问题

1、Session:每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大 2、扩展性:用户认证之后,服务端做认证记录,如果认证的记录被保存在内存的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,响应的限制了负载均衡器的能力,也意味着限制了应用的扩展性 3、CSRF:因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击

JWT的构成

JWT是由三部分构成(用.分隔),将这三段信息文本用链接构成了JWT字符串。就像这样

代码语言:javascript
复制
xxxxx.yyyyy.zzzzz

第一部分:头部(header) 第二部分:载荷(payload,该token里携带的有效信息。比如用户id、名字、年龄等等) 第三部分:签名(signature)

header

JWT的头部承载的两部分信息:

代码语言:javascript
复制
{
     'typ':'JWT', //声明类型,这里是jwt
     'alg':'HS256'  //声明加密的算法,通常直接使用HMAC SHA256或RSA
}

Header部分的JSON被Base64Url编码,形成JWT的第一部分。

代码语言:javascript
复制
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
plyload

这里放声明内容,可以说就是存放沟通讯息的地方,在定义上有3种声明(Claims):

  • Registered claims(注册声明): 这些是一组预先定义的声明,它们不是强制性的,但推荐使用,以提供一组有用的,可互操作的声明。 其中一些是:iss(发行者),exp(到期时间),sub(主题),aud(受众)等。
  • Public claims(公开声明): 这些可以由使用JWT的人员随意定义。 但为避免冲突,应在IANA JSON Web令牌注册表中定义它们,或将其定义为包含防冲突命名空间的URI。
  • Private claims(私有声明): 这些是为了同意使用它们但是既没有登记,也没有公开声明的各方之间共享信息,而创建的定制声明。 示例(这里存放的即使一个用户的信息,没有到期时间、主题之类的声明):
代码语言:javascript
复制
{
  "sub": "1234567890",
  "name": "Demo",
  "admin": true
}

Playload部分的JSON被Base64Url编码,形成JWT的第二部分。

代码语言:javascript
复制
请注意,对于已签名的令牌,此信息尽管受到篡改保护,但任何人都可以阅读。 除非加密,否则不要将秘密信息放在JWT的有效内容或标题元素中。第二部分不要放置敏感数据如银行卡帐号、身份证号等信息。一般存放用户ID、名字、是否管理员、拥有的权限等信息
Signature

第三部分signature用来验证发送请求者身份,由前两部分加密形成。 要创建签名部分,您必须采用编码标头,编码有效载荷,秘钥,标头中指定的算法并签名。

如果你想使用HMAC SHA256算法,签名将按照以下方式创建:

代码语言:javascript
复制
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload) + "." +
  secret)  

此secret存在于你的服务器端,打死都不要告诉任何人,否则就泄密了。

JWTs作为OAuth2.0关于Access_Token的具体解决方案, 为RFC 7519提出,但是后面又有个RFC 6750定义了Bearer Token,就是设置请求头:

代码语言:javascript
复制
Authorization: Bearer <token>
JWT常见问题

性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.

  1. JWT 安全嗎? Base64编码方式是可逆的,也就是透过编码后发放的Token内容是可以被解析的。一般而言,我们都不建议在有效载荷内放敏感讯息,比如使用者的密码。
  2. JWT Payload 內容可以被伪造嗎? JWT其中的一个组成内容为Signature,可以防止通过Base64可逆方法回推有效载荷内容并将其修改。因为Signature是经由Header跟Payload一起Base64组成的。
  3. 如果我的 Cookie 被窃取了,那不就表示第三方可以做 CSRF 攻击? 是的,Cookie丢失,就表示身份就可以被伪造。故官方建议的使用方式是存放在LocalStorage中,并放在请求头中发送。 但是放在LocalStorage中,退出浏览器后又得重新登录了,有利有弊吧
  4. 空间及长度问题? JWT Token通常长度不会太小,特别是Stateless JWT Token,把所有的数据都编在Token里,很快的就会超过Cookie的大小(4K)或者是URL长度限制

因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。(如果token是用cookie保存,CSRF还是需要考虑,一般建议使用1、在HTTP请求中以参数的形式加入一个服务器端产生的token。或者2.放入http请求头中也就是一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中)

建议: 1、不要存放敏感信息在Token里。 2、Payload中的exp时效不要设定太长。 3、开启Only Http预防XSS攻击。 4、在你的应用程序应用层中增加黑名单机制,必要的时候可以进行Block做阻挡(这是针对掉令牌被第三方使用窃取的手动防御)。

Java中使用JWT
代码语言:javascript
复制
<!--引入JWT依赖,由于是基于Java,所以需要的是java-jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

具体简单应用,参考博文:JWT在JAVA项目中的简单实际应用

详解OAuth2.0是什么(通俗易懂版)

OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式。

举个例子

你想登录豆瓣去看看电影评论,但你丫的从来没注册过豆瓣账号,又不想新注册一个再使用豆瓣,怎么办呢?不用担心,豆瓣已经为你这种懒人做了准备,用你的qq号可以授权给豆瓣进行登录,请看:

第一步:在豆瓣官网点击用qq登录

在这里插入图片描述
在这里插入图片描述

第二步:跳转到qq登录页面输入用户名密码,然后点授权并登录

在这里插入图片描述
在这里插入图片描述

第三步:跳回到豆瓣页面,成功登录

在这里插入图片描述
在这里插入图片描述

我们发现,我们竟然用QQ帐号登录进了豆瓣的系统里。到底发生了什么?

  • 小白视角(只会看表面现象): 就是在豆瓣官网上输了个qq号和密码就登录成功了。在一些细心的用户视角看来,页面经历了从豆瓣到qq,再从qq到豆瓣的两次页面跳转。
  • 上帝视角(程序员专业视角): 简单来说,上述例子中的豆瓣就是客户端QQ就是认证服务器,OAuth2.0就是客户端和认证服务器之间由于相互不信任而产生的一个授权协议。

呵呵,要是相互信任那QQ直接把自己数据库给豆瓣好了,你直接在豆瓣输入qq账号密码查下数据库验证就登陆呗,还跳来跳去的多麻烦

其实整个过程,用下面这一张图,就能上帝视角很清晰的看出来端倪:

在这里插入图片描述
在这里插入图片描述

备注:所用到的请求路径名称都是虚构的,所附带的请求参数忽略了一些非重点的。

  1. 第一步:在豆瓣官网点击用qq登录 当你点击用qq登录的小图标时,实际上是向豆瓣的服务器发起了一个 http://www.douban.com/leadToAuthorize 的请求,豆瓣服务器会响应一个重定向地址,指向qq授权登录

浏览器接到重定向地址 http://www.qq.com/authorize?callback=www.douban.com/callback,再次访问。并注意到这次访问带了一个参数是callback,以便qq那边授权成功再次让浏览器发起这个callback请求。不然qq怎么知道你让我授权后要返回那个页面啊,每天像豆瓣这样的需要QQ授权的网站这么多。

  1. 第二步:跳转到qq登录页面输入用户名密码,然后点授权并登录 上一步中浏览器接到重定向地址并访问 http://www.qq.com/authorize?callback=www.douban.com/callback

这时候来到的页面是QQ这边的登录授权页面。当访问QQ服务器验证用户名密码成功后,该方法会响应浏览器一个重定向地址,并附上一个code(**授权码**)。而这个授权码,就是豆瓣这边关心的了,因为豆瓣才不管QQ那边是怎么授权的呢。 3. 第三步:跳回到豆瓣页面,成功登录 这一步背后的过程其实是最繁琐的,但对于用户来说是完全感知不到的(所以你看页面上消耗的时间一般都比较长,长达好几秒)。用户在QQ登录页面点击授权登陆后,就直接跳转到豆瓣首页了,但其实经历了很多隐藏的过程。

QQ服务器在判断登录成功后,使页面重定向到之前豆瓣发来的callback的URL并且附上QQ自己提供的code授权码,即 callback=www.douban.com/callbackwithauthcode

当发送这个请求到豆瓣的服务器的时候,就复杂了,主要做了两件事(模拟了两次请求):

  1. 用拿到的授权码code去换token(和QQ服务器交互)
  2. 用拿到的token换取用户信息,比如用户名、头像等等信息(和QQ服务器交互) 最后信息拿到后,豆瓣这边就把你的信息存下来,返回到首页给你看。这样就完成了一套完整的授权。QQ服务器成功的把你的qq信息授权交给豆瓣了,完美
编码实现

其实Spring和OAuth是可以完美融合的使用的。Spring Cloud官方更是提供了starter进行天然支持。

具体编码过程,本文不做详解,具体参考博文:

基于Srping security Spring Cloud OAuth2(一) 搭建授权服务 Spring Cloud OAuth2(二) 扩展登陆方式:账户密码登陆、 手机验证码登陆、 二维码扫码登陆

理解OAuth和JWT的区别(通俗易懂)

1、oauth2有client和scope的概念,jwt没有。如果只是拿来用于颁布token的话,二者没区别。常用的bearer算法oauth、jwt都可以用。应用场景不同而已 2、Spring Cloud 的权限框架就是用的jwt实现的oauth2 。二者没有必然联系 3、Token功能不一样,JWT的token是包含用户基本信息的,然后通过加密的方式生成的字符串,服务器端拿到这个token之后不需要再去查询用户基本信息,解析完token之后就能拿到。想想在微服务架构下,用户服务是一个单独的服务,但是其他服务大部分情况下也会需要用户信息,难道要每次用到都去取一次吗? JWT非常适合微服务。 4、OAuth2用在使用第三方账号登录的情况(比如使用weibo, qq, github登录某个app)。OAuth2是一个相对复杂的协议, 有4种授权模式, 其中的access code模式在实现时可以使用jwt才生成code, 也可以不用. 它们之间没有必然的联系. 5、JWT是用在前后端分离, 需要简单的对后台API进行保护时使用.(前后端分离无session, 频繁传用户密码不安全) 6、JWT是一种认证协议 。JWT提供了一种用于**发布接入令牌(Access Token),**并对发布的签名接入令牌进行验证的方法。 令牌(Token)本身包含了一系列声明,应用程序可以根据这些声明限制用户对资源的访问。 7、OAuth2是一种授权框架。提供了一套详细的授权机制(指导)。用户或应用可以通过公开的或私有的设置,授权第三方应用访问特定资源。

JWT和Oauth2的应用场景的区别

jwt应用场景:

  • 无状态的分布式API JWT的主要优势在于使用无状态、可扩展的方式处理应用中的用户会话。服务端可以通过内嵌的声明信息,很容易地获取用户的会话信息,而不需要去访问用户或会话的数据库。在一个分布式的面向服务的框架中,这一点非常有用。

但是,如果系统中需要使用黑名单实现长期有效的token刷新机制,这种无状态的优势就不明显了(因为还是需要访问数据库,刷新时间啥的)

Oauth2应用场景:

  • 外包认证服务器 如果不介意API的使用依赖于外部的第三方认证提供者,你可以简单地把认证工作留给认证服务商去做。

常见的,去认证服务商(比如facebook)那里注册你的应用,然后设置需要访问的用户信息,比如电子邮箱、姓名等。当用户访问站点的注册页面时,会看到连接到第三方提供商的入口。用户点击以后被重定向到对应的认证服务商网站,获得用户的授权后就可以访问到需要的信息,然后重定向回来。

这种做法的优势:快速开发,实现代码量小,维护工作简单

  • 大型企业解决方案 如果设计的API要被不同的App使用,并且每个App使用的方式也不一样,使用OAuth2是个不错的选择。

优势:灵活的实现方式 ,可以和JWT同时使用,可针对不同应用扩展

ACCESS_TOKEN与FRESH_TOKEN之token的有效期问题

OAuth1.0中的access_token过期时间通常很长,安全性差。于是OAuth2.0推出了refresh_token。

OAuth2.0为了增强安全性,access token的有效期被大大缩短,通常只有几个小时,也可以申请增加到几十天,但是总是会有过期的时候。为此,OAuth2.0增加了一个refresh token的概念,这个token并不能用于请求api.它是用来在access token过期后刷新access token的一个标记.

为什么使用refresh_token而不是直接去获取一个新的access_token呢?

access_token的有效期一般都很短,几个小时到几天不等。如果这个时间已经过了,难道强制要求用户重新登录一次?那是不是体验太糟糕了。这个时候refresh_token就有用武之地了。

这个时候客户端就可以通过refresh_token获得新的access_token,expire_in,与refresh_token。 周而复始,你的token的有效期就能被明显延长了

这里所描述的场景,通常是指那种长周期的应用.也就是需要一直保持用户在线的应用. 在线并不是说用户一直在用这个应用,也可能是用户已经离开,我们在后台仍然可以自动维持用户的状态.例如一个自动发状态的应用.用户并不需要操作这个应用,我们会定时在后台利用用户的accesskey帮助用户发送状态.这也算是用户维持登录状态的一种.

因此如果你的refresh_token有效期是1个月,你只需要每个月帮用户发一条状态的话,走上面的流程,一直下去,这个用户的登录状态一直都不会过期。(App移动端就可以这么来实现)

JWT是怎么解决token过期时间问题的呢?

这篇文章,你值得拥有: JWT(JSON Web Token)自动延长到期时间

细节:

1、为了不能一个帐号多次登录,因此当别地获取到一个新的token时候,之前的token需要作废,不能够在使用(做得更好一点,可以通知另外一端强制下线。参考QQ俩PC端同时登录的情况) 2、token的过期时间的设置 也一定要谨慎

总结

总而言之,Oauth2和jwt是完全不同的两种东西,一个是授权认证的框架,另一种则是认证验证的方式方法(轻量级概念)。OAuth2不像JWT一样是一个严格的标准协议,因此在实施过程中更容易出错。尽管有很多现有的库,但是每个库的成熟度也不尽相同,同样很容易引入各种错误。在常用的库中也很容易发现一些安全漏洞。

注意: 两种方案都需要SSL安全保护,也就是对要传输的数据进行加密编码。安全地传输用户提供的私密信息,在任何一个安全的系统里都是必要的。否则任何人都可以通过侵入私人wifi,在用户登录的时候窃取用户的用户名和密码等信息。

安全这个概念都是相对的,没有绝对的。比如服务端自己掌握着加密值,但万一这个值被泄漏了呢?别人还是可以破译你的JWT了。但是加上SSL的话,安全性就大大增加了

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年11月10日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是OAuth
  • 什么是JWT
  • 详解JWT
    • 基于session认证所显露的问题
      • JWT的构成
        • header
          • plyload
            • Signature
              • JWT常见问题
              • Java中使用JWT
              • 详解OAuth2.0是什么(通俗易懂版)
                • 举个例子
                  • 编码实现
                  • 理解OAuth和JWT的区别(通俗易懂)
                  • JWT和Oauth2的应用场景的区别
                  • ACCESS_TOKEN与FRESH_TOKEN之token的有效期问题
                    • 为什么使用refresh_token而不是直接去获取一个新的access_token呢?
                    • JWT是怎么解决token过期时间问题的呢?
                      • 细节:
                      • 总结
                      相关产品与服务
                      访问管理
                      访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档