本文转载自微信公众号《Java极客技术》,作者鸭血范。转载本文请联系Java极客技术公众号。授权机制,说到这个问题,大家对它的第一印象在哪里?是培训机构教的SSO单点登录吗?对,还有这种SSO单点登录点击登录。当年的培训机构都是用sessionsharing,就是用Redis作为中间模拟session,但是授权机制真的有那么简单吗?接下来,阿芬就授权机制做一个强势对比。Cookie-Session认证与授权Cookie-Session认证机制是在服务端创建一个Session对象对一个请求进行认证,在客户端浏览器端创建一个Cookie对象;Cookie对象由客户端提出来匹配服务器端的会话对象进行状态管理。但是这时候我们就不得不考虑cookies的存活时间了。当我们关闭浏览器时,cookies将被删除。即使我们调整了cookies的生存时间,它仍然有很多缺点。Cookies很容易被拦截,之前阿芬看过一个比较有名的OA系统,把用户的ID放在cookie里,但是把cookie里的key设置为imageUrl,但其实这样的看起来有点烦.图片地址是一串长字符串。你在前端拦截之后,明眼人一看就知道,这绝对不是图片路径,而当我们使用cookie进行用户身份识别时,用户会很容易受到跨站请求伪造,这也就是我们常说的CSRF。既然这里将JWT与JWT进行对比,那么我们首先要知道什么是JWT。JSONWebToken(JWT)其实是一种Authentication机制,让后台知道这个请求来自一个可信的客户端。技术伴随着问题出现。只要有问题,很快就会有解决这个问题的技术。同样的,JWT也是出现的比较早,因为现在微服务是分布式的,泛滥成灾。许多公司,甚至是小公司,都开始做分布式项目。这个分布式项目不仅限于大公司。由于他们选择使用分布式项目,因此出现了各种问题。跨域身份验证分布式session共享分布式站点的单点登录JWT是个什么玩意我们先看一下官方网站给的内容,WhatisJSONWebToken?JSONWebToken(JWT)isanopenstandard(RFC7519)thatdefinesacompactandself-containedwayforsecurelytransmittinginformationbetweenpartiesasaJSONobject.Thisinformationcanbeverifiedandtrustedbecauseitisdigitallysigned.JWTscanbesignedusingasecret(withtheHMACalgorithm)orapublic/privatekeypairusingRSAorECDSAJSONWebToken(JWT)isanopenstandard(RFC7519)thatdefinesacompactandself-containedwaytosecurelytransmitinformationbetweenpartiesasJSONobjects.Sincetheinformationisdigitallysigned,itcanbeverifiedandtrusted.JWTscanbesignedusingasecret(usingtheHMACalgorithm)orusinganRSAorECDSApublic/privatekeypair.AhFendirectlytranslateditwithBaidu,andthetranslationwasalmostthesame.ItseemsthatBaidutranslationsometimesdoesnotThatsucks.SowhendoyouneedtouseJWT?Ontheofficialwebsite,twosituationsaregiventouseJWT,AuthorizationandInformationExchange.Oneisauthorization.Weallunderstandauthorization,thatis,aftertheuserlogsin,eachsubsequentrequestwillbeIncludingJWT,whichallowsuserstoaccesstheroutes,servicesandresourcesallowedbythetoken,andresourceexchange,infact,issimplytouseJWTtokenstosecurelytransmitinformationbetweenpartiesduringdatatransmission.Nowthatweknow了什么时候来使用JWT,我们就来看看JWT到底是长成什么样子,JWT构成:Header头部Payload有效载荷Signature签名我们从官网上获取了一段的内容,然后逐个来看,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cSinceitsaysthatJWTiscomposedofthreepiecesofinformation,andthesethreepiecesofinformationareseparatedby.Yes,whatisstoredintheHeaderisactuallythecontentof2parts.typ:typealg:encryptionalgorithm,andthenitbase64-encryptstheheader.Iamthecontentofthefirstparagraphwepickedfromtheofficialwebsite,andtheencryptedstringeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9appears.Payloadpayload其实就是存放有效信息的地方,那么它存放的是什么呢?iss(issuer):issuerexp(expirationtime):过期时间sub(subject):subjectaud(audience):Audiencenbf(NotBefore):生效时间iat(IssuedAt):发行时间jti(JWTID):number(jwt的唯一标识,主要作为一次性token使用,避免重放攻击)为什么会有这么多,因为在JWT规范中,他告诉我们推荐但不强制,也就是说,大家可以根据自己的应用选择使用,比如官网,他没有写的很全面,直接使用就可以了三:{"sub":"1234567890","name":"JohnDoe","iat":1516239022}其实这部分的内容比较重要。签名签名信息实际上是组装的。标头和有效载荷用“.”连接。sign,再加上一串keys,通过header中声明的加密算法进行加密,然后签名。Header和Payload都是加密的,在这个地方还进行了“加盐”的操作,将这三部分用.成一个完整的字符串,形成最终的jwtjwt。在很多技术人员看来,测试的技术可能会觉得会很low。其实虽然算不上高端,但也没有那么low。身份验证服务器使用对称或非对称加密从有效载荷生成签名并将其放入标头中。申明签名方法,这是JWT必不可少的实现方法。JWT的优势其实很明显。通过验证签名,可以直接在资源服务器本地完成授权验证。payload中可以包含用户相关信息,实现token和用户信息的绑定。使用场景一般用于一次性身份验证方面,不要想着用JWT代替Session。JWT虽然可以设置过期时间,但是不能在有效期内作废。OAuth2身份验证OAuth引入了一个授权层来分隔两个不同的角色:客户端和资源所有者。资源所有者同意后,资源服务器可以向客户端颁发令牌。客户端通过令牌请求数据。其实这个OAuth的核心就是给第三方应用颁发token,而在Oauth2中定义了四个获取token的过程,也就是现在流行的四种授权方式,但是我们经常使用的是那个。AuthorizationCodeHidden(simplified)PasswordClientCredentialsAuthorizationCodeMode这是Oauth中功能最全、流程最严格的授权方式。授权码方式的步骤:1.用户访问客户端,后者将前者指向认证服务器2.用户选择是否授权客户端3.假设用户授权,认证服务器将用户指向客户端预先指定的“重定向URI”(redirectionURI),同时附上授权码4.客户端收到授权码,附上之前的“重定向URI”,申请token进行鉴权服务器,这一步是在客户端的后台服务器上完成的,用户是不可见的5.认证服务器检查授权码和重定向URI,确认无误后,发送访问令牌(accesstoken)而更新令牌(refreshtoken)授权码模式其实相当于第三方应用先申请授权码,然后使用授权码获取token。总结一下,有四步:1:请求授权码2:返回授权码3:请求token4:返回token举个例子,然后分析。https://2.com/oauth/authorize?//授权地址response_type=code&//参数1:response_type:表示授权类型,这里的值固定为“code”client_id=CLIENT_ID&//参数2:client_id:表示客户端的IDredirect_uri=CALLBACK_URL&//参数3:redirect_uri:表示重定向URLscope=read//参数4:scope:表示应用权限范围以上的地址,相当于第一步,携带请求网站所需的参数2.请求授权码。https://1.com/callback?code=AUTHORIZATION_CODE//code授权码上面的地址是第二步。网站2返回给网站1的授权码,https://2.com/oauth/token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&clientkeygrant_type=authorization_code&usedauthorizationmodeauthorization_code:authorizationcodemodecode=AUTHORIZATION_CODE&authorizationcoderedirect_uri=CALLBACK_URL表示地址重定向网址上方是第三步,使用授权码请求订单卡请求发送。请求发送后,2网站收到请求后,向重定向URL发送如下JSON数据,{"access_token":"ACCESS_TOKEN",//accesstoken"token_type":"bearer",//orderCardtype"expires_in":2592000,//过期时间"refresh_token":"REFRESH_TOKEN",//更新令牌"scope":"read",//权限范围只读"uid":100101,//"info":{...}//}这时候,我们就得到了accesstoken。完成所有的步骤之后,我们就会得到我们的accesstoken,也就是我们完成了需要的授权。hidden其实是授权模式的简化版,省略了获取授权码的过程,而是直接请求获取token的过程。案例如下:https://2.com/oauth/authorize?response_type=token&授权类型,这里的值固定为"token"client_id=CLIENT_ID&clientIDredirect_uri=CALLBACK_URL&表示重定向URLscope=read权限范围只读上面的授权类型是直接要token,第二步也很简单,就是直接返回你需要的tokenhttps://1.com/callback#token=ACCESS_TOKEN上面的token就是我们需要的token,password这种方法之所以叫做password类型是因为它在请求请求的时候使用密码来交换token。这需要一个前提,即您对本网站具有较高的可信度。你不信任他,他给你的账号密码用处不大,给你Token也不授权吧?案例步骤如下:1.请求tokenhttps://oauth.2.com/token?grant_type=password&授权方式:指定为密码username=USERNAME&usernamepassword=PASSWORD&passwordclient_id=CLIENT_ID客户端ID2.返回tokenhttps://1.com/callback#token=ACCESS_TOKEN这种感觉和隐藏的没太大区别。一种是直接求,一种是带参数求。凭证类型这种凭证类型的步骤相对较少。其实阿芬觉得这种方式并不是授权方式,因为这种方式是客户端向自己名下的“授权服务商”进行认证。不过既然说是,我们暂且假设他是,1:请求tokenhttps://oauth.2.com/token?grant_type=client_credentials&authorizationmethod:credentialclient_id=CLIENT_ID&clientIDclient_secret=CLIENT_SECRETclientkey2.返回tokenhttps://1.com/callback#token=ACCESS_TOKEN这种方式给出的token是给第三方应用的,不是给用户的,也就是说多个用户可能共享同一个token。为什么要比较JWT和Oauth2,因为很多不懂的人在选择技术的时候总会比较两者。其实它们没有可比性,因为JWT是用来颁发accesstoken的,而且是验证颁发的signedaccesstoken的方法。OAuth2是授权第三方应用程序访问特定资源的授权框架。也就是说:OAuth2用于第三方账号登录。JWT用于前后端分离。它需要简单地保护后台API。那么你知道如何选择吗?文章参考《阮一峰的网络日志》《JWT官方文档》
