当前位置: 首页 > 后端技术 > PHP

OAuth2

时间:2023-03-29 18:55:31 PHP

为什么需要oAuth2?假设有一款“云笔记”产品,提供“云笔记服务”和“云相册服务”。)来访问这些“资源”(笔记、图片),那么用户如何访问自己的部分资源呢?这时候传统的做法是向我们的“云笔记”提供自己的账号和密码,登录成功后即可获取资源。但是这种方式会存在以下问题:“云笔记服务”和“云相册服务”会分开部署,我们是不是要分别登录?如果有第三方应用要访问我们的“云笔记”,用户是不是需要向第三方应用提供账号和密码,记录后才能访问我们的资源?用户如何在我们的“云笔记”中限制第三方应用的授权范围和使用期限?是否可以将所有数据永久暴露给它?如果用户修改密码并撤销权限,则所有第三方应用程序将失效。只要一个连接的第三方应用被破解,用户的密码就会被泄露,后果不堪设想。解决上述问题的oAuth2是什么oAuth2应用?OAuth(OpenAuthorization)是一种开放标准,允许用户授权第三方移动应用程序访问他们存储在另一个服务提供商上的信息,而无需向第三方移动应用程序提供用户名和密码或共享其数据的所有内容,OAuth2.0是OAuth协议的延续,但不向后兼容OAuth1.0,即OAuth1.0被彻底废除。OAuth2.0的标准是RFC6749文档。该文档首先解释了OAuth引入了一个授权层来分隔两个不同的角色:客户端和资源所有者。...资源所有者同意后,资源服务器可以向客户端颁发令牌。客户端通过令牌请求数据。OAuth的核心是向第三方应用程序颁发令牌。oAuth2条规则中名词解释第三方应用:也称为客户端(client),比如上一节提到的设备(PC、Android、iPhone、TV、Watch),我们会安装我们自己的在这些设备上开发了APP。再比如我们的产品要使用QQ、微信等第三方登录。对于我们的产品,QQ和微信登录是第三方登录系统。我们还需要第三方登录系统的资源(头??像,昵称等)。QQ、微信等系统,我们是第三方应用。HTTP服务商(HTTP服务):我们的云笔记产品,QQ,微信等都可以称为“服务商”。资源所有者:也称为用户。用户代理(UserAgent):比如浏览器,代表用户访问这些资源。认证服务器(Authorizationserver):即服务提供者专门用来处理认证的服务器。简单的说就是登录功能(验证用户的账号密码是否正确,并分配相应的权限)资源服务器(Resourceserver):即服务提供者托管用户生成资源的服务器。它和认证服务器可以是同一台服务器,也可以是不同的服务器。简单来说,就是资源的接入入口。比如上一节提到的“云笔记服务”和“云相册服务”都可以称为资源服务器。oAuth2规则的操作(A)用户打开客户端后,客户端要求用户授权。(B)用户同意授权给客户端。(C)客户端使用上一步获得的授权向认证服务器申请token。(D)认证服务器对客户端进行认证后,确认无误,同意颁发令牌。(E)客户端使用token向资源服务器申请资源。(F)资源服务器确认token无误,同意向客户端开放资源。oAuth2规则的客户端授权方式授权码方式(authorizationcode)(A)用户访问客户端,后者将前者指向认证服务器。(B)用户选择是否授权客户端。(C)假设用户授权,认证服务器将用户定向到客户端事先指定的“重定向URI”(redirectionURI),同时附上一个授权码。(D)客户端收到授权码,附上之前的“重定向URI”,向认证服务器申请token。该步骤在客户端后台在服务器端完成,用户不可见。(E)认证服务器检查授权码和重定向URI,确认无误后,向客户端发送访问令牌(accesstoken)和刷新令牌(refreshtoken)。简化模式(隐式)(A)客户端将用户定向到身份验证服务器。(B)用户决定是否授权客户端。(C)假设用户授予授权,认证服务器将用户定向到客户端指定的“重定向URI”,并在URI的Hash部分包含访问令牌。(D)浏览器向资源服务器发送请求,其中不包含上一步收到的Hash值。(E)资源服务器返回网页,网页中包含获取Hash值中token的代码。(F)浏览器执行上一步得到的脚本提取token。(G)浏览器向客户端发送令牌。密码模式(资源所有者密码凭证)(A)用户向客户端提供用户名和密码。(B)客户端将用户名和密码发送给认证服务器,并向后者请求令牌。(C)认证服务器确认无误后,将accesstoken提供给客户端。客户端模式(客户端凭据)(A)客户端向身份验证服务器进行身份验证并请求访问令牌。(B)认证服务器确认无误后,将accesstoken提供给客户端。oAuth2客户端授权码模式详细步骤授权码模式(authorizationcode)是目前功能最全、流程最严谨的授权模式。其特点是通过客户端的后台服务器与“服务提供者”的认证服务器进行交互。(A)用户访问客户端,后者将前者指向认证服务器;客户端申请认证的URI包含如下参数:response_type:授权类型,必填,这里的值固定为“code”client_id:客户端ID,必填redirect_uri:重定向URI,可选scope:表示应用的权限范围,optionalstate:表示客户端当前状态,任意字符串,认证服务器会原封不动的返回这个值,也用于防止跨站请求伪造攻击,requiredoptioneg:GET/authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2FcbHTTP/1.1(B)用户选择是否授权客户端。(c)假设用户授权,认证服务器将用户定向到客户端事先指定的“重定向URI”(redirectionURI),并附上授权码;服务器响应客户端的URI,包括以下参数:code:授权码,必填。这段代码的有效期应该很短,一般设置为10分钟,客户端只能使用一次这段代码,否则会被授权服务器拒绝。代码与客户端ID和重定向URI之间存在一一对应关系。state:如果客户端的请求中包含该参数,则认证服务器的响应也必须包含该参数。eg:Location:https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz(D)客户端收到授权码,附加前面的“重定向URI”,向认证服务器请求令牌。该步骤在客户端后台服务器完成,用户不可见;客户端向认证服务器请求token的HTTP请求包含以下参数:code:表示上一步获取的授权码,必填。redirect_uri:表示redirectURI应用中的URL,用于用户授权后发送,必填,必须与步骤A中的参数值一致。client_id:表示应用的客户端ID,必填。client_secret:表示应用的clientsecret,即访问资源权限。必需,例如:POST/tokenHTTP/1.1主机:server.example.com授权:基本czZCaGRSa3F0MzpnWDFmQmF0M2JW内容类型:application/x-www-form-urlencodedgrant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb(E)认证服务器检查了授权码和重定向URI,确认无误后,向客户端发送访问令牌(accesstoken)和更新令牌(refreshtoken);认证服务器发送的HTTP回复包含以下参数:access_token:accesstoken,必填。token_type:令牌类型,取值不区分大小写,必填,可以是bearertype或mactype。expires_in:表示过期时间,单位秒。如果省略该参数,则必须通过其他方式设置过期时间。refresh_token:表示refreshtoken,用于获取下一个accesstoken,可选。scope:表示权限范围,如果与客户端申请的范围一致,此项可以省略。例如:HTTP/1.1200OKContent-Type:application/json;charset=UTF-8Cache-Control:no-storePragma:no-cache{“access_token”:“2YotnFZFEjr1zCsicMWpAA”,“token_type”:“example”,“expires_in":3600,"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA","example_parameter":"example_value"}更新token的流程图如下。令牌的有效期已到。如果用户再走一遍上面的流程,再去申请一个新的Token,体验很可能不好,也没有必要。OAuth2.0允许用户自动更新令牌。具体做法是,资源服务器在发布token时,一次发布两个token,一个用于获取数据,一个用于获取新的token(刷新token字段)。在令牌过期之前,用户使用刷新令牌发送更新令牌的请求。https://b.com/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKENURL,grant_type参数为refresh_token表示需要更新token,client_id和client_secret参数用于确认identity,refresh_token参数是用来更新token的token。资源服务器通过身份验证后,将颁发一个新的令牌。oAuth2四种方式比对密码模式(资源所有者密码凭证)这种模式是最不推荐的,因为客户端可能已经保存了用户密码。该模式主要用于遗留项目升级到oauth2。当然,如果客户端是自己的应用,也可以支持refreshtoken授权码方式(authorizationcode)。该模式是一种地道的oauth2授权模式。设计了authcode,通过此代码获取token,支持refreshtoken简化模式(隐式)。这种模式比授权码更高效该模式缺少代码链接,回调url直接携带token。该模式的使用场景以浏览器的应用为准。这种模式是基于安全的考虑。建议将tokenaging设置的更短一些。不支持刷新令牌客户端模式(客户端凭据)。这种模式可以直接根据客户端的id和key获取token,不需要用户参与。这种模式比较适合消费API的后端服务,比如拉取一组用户信息等不支持refreshtoken,主要是因为不需要refreshtoken本意主要是为了用户体验和不希望用户重复输入账号密码换取新的token,所以refreshtoken就是为了换取新的token而设计的。这种模式不需要用户参与,也不需要用户帐号密码,只根据自己的id和密码。key可以换成新的token,所以不需要刷新tokensecurityquestionredirect_uri问:为什么OAuth2.0在申请client_id的时候需要输入域名,而且redirect_uri必须是这个域名下的地址?答:如果别人知道我们的client_id,那么在第二部分生成授权连接的时候,把redirect_uri换成你自己域名下的,就可以拿到code,存放在自己的服务器上。如果第三方服务不支持https,会有被劫持的风险。如果没有代码,直接在redirect_uri中返回access_token,中间人可以直接使用access_tokenapp_secret。如果code是中间人拿到的,在没有app_secret的情况下,可以直接用code换取access_token。因为在整个代码获取过程中暴露的state参数如果作为CSRFToken可以避免:攻击者仍然获取了代码并打算诱骗受害者点击链接,但是由于服务器(例如chrisyue.com)到受害者设备的链接中的状态值不同。服务端(chrisyue.com)直接返回验证状态失败`state`或者绑定设备的`CSRFToken`只要稍微复杂一点,攻击者是不可能猜到随机字符串的。设置一个状态(CSRF令牌)值绑定到攻击者无法猜测的设备或浏览器是解决方案。CSRF攻击的关键。oAuth2的实现过程总结Auth2的实现机制是不同的客户端需要向资源服务器请求token(access_token)来获取不同的资源,服务器需要验证访问的客户端是否在资源服务器注册过,以及资源服务器分配给客户端的访问权限是多少,所以需要先由客户端将用户重定向到认证服务器验证其身份。验证通过后,返回一个只能用于获取token的token,每次一个code代码,作为请求token的参数。客户端在请求token时,还必须传递一个必须要获取资源权限的参数client_secrect,以及参数client_id(客户端的身份)。如果验证通过,则客户端获取资源并显示给用户。参考资料:https://www.jianshu.com/p/a7d...http://www.ruanyifeng.com/blo...http://www.ruanyifeng.com/blo...http://www.ruanyifeng.com/blo...http://www.ruanyifeng.com/blo...https://developer.github.com/...https://www.jianshu.com/p/7b1...