oauth2.0_oauth2.0协议 - CSDN
精华内容
参与话题
  • OAuth 2.0 详细介绍

    千次阅读 2018-09-05 14:52:47
    OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749。 一、应用场景 为了...

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

    本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749

    OAuth Logo

    一、应用场景

    为了理解OAuth的适用场合,让我举一个假设的例子。

    有一个"云冲印"的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让"云冲印"读取自己储存在Google上的照片。

    云冲印

    问题是只有得到用户的授权,Google才会同意"云冲印"读取这些照片。那么,"云冲印"怎样获得用户的授权呢?

    传统方法是,用户将自己的Google用户名和密码,告诉"云冲印",后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。

    (1)"云冲印"为了后续的服务,会保存用户的密码,这样很不安全。

    (2)Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。

    (3)"云冲印"拥有了获取用户储存在Google所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。

    (4)用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。

    (5)只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

    OAuth就是为了解决上面这些问题而诞生的。

    二、名词定义

    在详细讲解OAuth 2.0之前,需要了解几个专用名词。它们对读懂后面的讲解,尤其是几张图,至关重要。

    (1) Third-party application:第三方应用程序,本文中又称"客户端"(client),即上一节例子中的"云冲印"。

    (2)HTTP service:HTTP服务提供商,本文中简称"服务提供商",即上一节例子中的Google。

    (3)Resource Owner:资源所有者,本文中又称"用户"(user)。

    (4)User Agent:用户代理,本文中就是指浏览器。

    (5)Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。

    (6)Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

    知道了上面这些名词,就不难理解,OAuth的作用就是让"客户端"安全可控地获取"用户"的授权,与"服务商提供商"进行互动。

    三、OAuth的思路

    OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)。"客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。

    "客户端"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。

    四、运行流程

    OAuth 2.0的运行流程如下图,摘自RFC 6749。

    OAuth运行流程

    (A)用户打开客户端以后,客户端要求用户给予授权。

    (B)用户同意给予客户端授权。

    (C)客户端使用上一步获得的授权,向认证服务器申请令牌。

    (D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。

    (E)客户端使用令牌,向资源服务器申请获取资源。

    (F)资源服务器确认令牌无误,同意向客户端开放资源。

    不难看出来,上面六个步骤之中,B是关键,即用户怎样才能给于客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。

    下面一一讲解客户端获取授权的四种模式。

    五、OAuth2.0客户端授权模式

    客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。

    OAuth2.0 协议根据使用不同的适用场景,定义了用于四种授权模式。

    Authorization code(授权码模式)
    标准的 Server 授权模式,非常适合 Server 端的 Web 应用。一旦资源的拥有者授权访问他们的数据之后,他们将会被重定向到 Web 应用并在 URL 的查询参数中附带一个授权码(code)。在客户端里,该 code 用于请求访问令牌(access_token)。并且该令牌交换的过程是两个服务端之前完成的,防止其他人甚至是资源拥有者本人得到该令牌。另外,在该授权模式下可以通过 refresh_token 来刷新令牌以延长访问授权时间,也是最为复杂的一种方式。

    Implicit Grant(隐式模式)
    该模式是所有授权模式中最简单的一种,并为运行于浏览器中的脚本应用做了优化。当用户访问该应用时,服务端会立即生成一个新的访问令牌(access_token)并通过URL的#hash段传回客户端。这时,客户端就可以利用JavaScript等将其取出然后请求API接口。该模式不需要授权码(code),当然也不会提供refresh token以获得长期访问的入口。

    Resource Owner Password Credentials(密码模式)
    自己有一套用户体系,这种模式要求用户提供用户名和密码来交换访问令牌(access_token)。该模式仅用于非常值得信任的用户,例如API提供者本人所写的移动应用。虽然用户也要求提供密码,但并不需要存储在设备上。因为初始验证之后,只需将 OAuth 的令牌记录下来即可。如果用户希望取消授权,因为其真实密码并没有被记录,因此无需修改密码就可以立即取消授权。token本身也只是得到有限的授权,因此相比最传统的 username/password 授权,该模式依然更为安全。

    Client Credentials(客户端模式)
    没有用户的概念,一种基于 APP 的密钥直接进行授权,因此 APP 的权限非常大。它适合像数据库或存储服务器这种对 API 的访问需求。

    六、授权码模式

    授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。

    授权码模式

    它的步骤如下:

    (A)用户访问客户端,后者将前者导向认证服务器。

    (B)用户选择是否给予客户端授权。

    (C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。

    (D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。

    (E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

    下面是上面这些步骤所需要的参数。

    A步骤中,客户端申请认证的URI,包含以下参数:

    • response_type:表示授权类型,必选项,此处的值固定为"code"
    • client_id:表示客户端的ID,必选项
    • redirect_uri:表示重定向URI,可选项
    • scope:表示申请的权限范围,可选项
    • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

    下面是一个例子。

    
    GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
            &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com
    
    

    C步骤中,服务器回应客户端的URI,包含以下参数:

    • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
    • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

    下面是一个例子。

    
    HTTP/1.1 302 Found
    Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
              &state=xyz
    
    

    D步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:

    • grant_type:表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
    • code:表示上一步获得的授权码,必选项。
    • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
    • client_id:表示客户端ID,必选项。

    下面是一个例子。

    
    POST /token HTTP/1.1
    Host: server.example.com
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
    &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
    
    

    E步骤中,认证服务器发送的HTTP回复,包含以下参数:

    • access_token:表示访问令牌,必选项。
    • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
    • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
    • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
    • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

    下面是一个例子。

    
         HTTP/1.1 200 OK
         Content-Type: application/json;charset=UTF-8
         Cache-Control: no-store
         Pragma: no-cache
    
         {
           "access_token":"2YotnFZFEjr1zCsicMWpAA",
           "token_type":"example",
           "expires_in":3600,
           "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
           "example_parameter":"example_value"
         }
    
    

    从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。

    七、简化模式

    简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

    简化模式

    它的步骤如下:

    (A)客户端将用户导向认证服务器。

    (B)用户决定是否给于客户端授权。

    (C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。

    (D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。

    (E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。

    (F)浏览器执行上一步获得的脚本,提取出令牌。

    (G)浏览器将令牌发给客户端。

    下面是上面这些步骤所需要的参数。

    A步骤中,客户端发出的HTTP请求,包含以下参数:

    • response_type:表示授权类型,此处的值固定为"token",必选项。
    • client_id:表示客户端的ID,必选项。
    • redirect_uri:表示重定向的URI,可选项。
    • scope:表示权限范围,可选项。
    • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

    下面是一个例子。

    
        GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
            &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
        Host: server.example.com
    
    

    C步骤中,认证服务器回应客户端的URI,包含以下参数:

    • access_token:表示访问令牌,必选项。
    • token_type:表示令牌类型,该值大小写不敏感,必选项。
    • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
    • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
    • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

    下面是一个例子。

    
         HTTP/1.1 302 Found
         Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
                   &state=xyz&token_type=example&expires_in=3600
    
    

    在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。

    根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。

    八、密码模式

    密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

    在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

    密码模式

    它的步骤如下:

    (A)用户向客户端提供用户名和密码。

    (B)客户端将用户名和密码发给认证服务器,向后者请求令牌。

    (C)认证服务器确认无误后,向客户端提供访问令牌。

    B步骤中,客户端发出的HTTP请求,包含以下参数:

    • grant_type:表示授权类型,此处的值固定为"password",必选项。
    • username:表示用户名,必选项。
    • password:表示用户的密码,必选项。
    • scope:表示权限范围,可选项。

    下面是一个例子。

    
         POST /token HTTP/1.1
         Host: server.example.com
         Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
         Content-Type: application/x-www-form-urlencoded
    
         grant_type=password&username=johndoe&password=A3ddj3w
    
    

    C步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。

    
         HTTP/1.1 200 OK
         Content-Type: application/json;charset=UTF-8
         Cache-Control: no-store
         Pragma: no-cache
    
         {
           "access_token":"2YotnFZFEjr1zCsicMWpAA",
           "token_type":"example",
           "expires_in":3600,
           "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
           "example_parameter":"example_value"
         }
    
    

    上面代码中,各个参数的含义参见《授权码模式》一节。

    整个过程中,客户端不得保存用户的密码。

    九、客户端模式

    客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。

    客户端模式

    它的步骤如下:

    (A)客户端向认证服务器进行身份认证,并要求一个访问令牌。

    (B)认证服务器确认无误后,向客户端提供访问令牌。

    A步骤中,客户端发出的HTTP请求,包含以下参数:

    • granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
    • scope:表示权限范围,可选项。
    
         POST /token HTTP/1.1
         Host: server.example.com
         Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
         Content-Type: application/x-www-form-urlencoded
    
         grant_type=client_credentials
    
    

    认证服务器必须以某种方式,验证客户端身份。

    B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。

    
         HTTP/1.1 200 OK
         Content-Type: application/json;charset=UTF-8
         Cache-Control: no-store
         Pragma: no-cache
    
         {
           "access_token":"2YotnFZFEjr1zCsicMWpAA",
           "token_type":"example",
           "expires_in":3600,
           "example_parameter":"example_value"
         }
    
    

    上面代码中,各个参数的含义参见《授权码模式》一节。

    十、更新令牌

    如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌。

    客户端发出更新令牌的HTTP请求,包含以下参数:

    • granttype:表示使用的授权模式,此处的值固定为"refreshtoken",必选项。
    • refresh_token:表示早前收到的更新令牌,必选项。
    • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。

    下面是一个例子。

    
         POST /token HTTP/1.1
         Host: server.example.com
         Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
         Content-Type: application/x-www-form-urlencoded
    
         grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
    
    展开全文
  • OAuth2.0 原理流程及其单点登录和权限控制

    万次阅读 多人点赞 2018-07-27 11:51:00
    本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。 作者:王克锋 出处:https://kefeng.wang/2018/04/06/oauth2-sso/ ...

    单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。

    作者:王克锋
    出处:https://kefeng.wang/2018/04/06/oauth2-sso/
    版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。

    1 什么是单点登录

    1.1 多点登录

    传统的多点登录系统中,每个站点都实现了本站专用的帐号数据库和登录模块。各站点的登录状态相互不认可,各站点需要逐一手工登录。如下图,有两个术语含义如下:

    • 认证(authentication): 验证用户的身份;
    • 授权(authorization): 验证用户的访问权限。

    1.2 单点登录

    单点登录,英文是 Single Sign On,缩写为 SSO。
    多个站点(192.168.1.20X)共用一台认证授权服务器(192.168.1.110,用户数据库和认证授权模块共用)。用户经由其中任何一个站点(比如 192.168.1.201)登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。

    2 OAuth2 认证授权的原理流程

    2.1 生活实例【★★重点★★】

    为了直观的理解 OAuth2.0 原理流程,我们假设这样一个生活场景:
    (1)档案局A(客户端 / Client):以“档案局ID/密码”标识,是掌握档案资源的机构。并列还有很多档案局B/C/…,每个档案局存储的档案内容(资源 / Resource)不一样,比如政治、经济、军事、文化等;
    (2)公民张三(资源所有者 / Resource Owner):以“用户名/密码”标识,需要到各个档案局查档案;
    (3)派出所(授权服务器 / Authentication Server):可以是单个巨大的派出所,也可以是数据共享的派出所集群,掌管的信息、提供的对外接口功能有:

    • 档案局信息:所有档案局的“档案局ID/密码”,证明档案局的身份;
    • 公民信息:所有公民的“用户名/密码”,能提供张三是张三的用户身份证明(认证 / Authentication)
    • 公民对于档案局的权限:有张公民和档案局的权限的映射表,可查得各公民对各档案局是否有操作权限(授权 / Authorization)。通常,设计中会增加官职(角色 / Role)一层,各公民属于哪个官职(角色),哪个官职(角色)对于特定档案局有操作权限。

    2.1.1 张三首次访问档案局A

    张三之前从未到访档案局,第一次来档案局。对照下图序号理解:
    (1)张三来到“档案局A”的“档案处”,该处要求实名登记后才能查询,被指示到“用户登记处”办理(HTTP重定向);
    (2)张三来到“档案局A”的“用户登记处”,既不能证明身份(认证),又不能证明自己有查档案A的权限(授权)。张三携带档案局A的标识(client-id),被重定向至“授权信开具处”;
    (3)张三来到“派出所”的“授权信开具处”,出示档案局A的标识,希望开具授权信(授权)。该处要求首先证明身份(认证),被重定向至“用户身份验证处”;
    (4)张三来到“派出所”的“用户身份验证处”,领取了用户身份表(网页登录表单 Form);
    (5)张三填上自己的用户名和密码,交给(提交 / Submit)“用户身份验证处”,该处从私用数据库中查得用户名密码匹配,确定此人是张三,开具身份证明信,完成认证。张三带上身份证明信和档案局A的标识,被重定向至“授权信开具处”;
    (6)张三再次来到“授权信开具处”,出示身份证明信和档案局A的标识,该处从私用数据库中查得,张三的官职是市长级别(角色),该官职具有档案局A的查询权限,就开具“允许张三查询档案局A”的授权信(授权码 / code),张三带上授权信被重定向至“档案局”的“用户登录处”;
    (7)张三到了“档案局”的“用户登录处”,该处私下拿出档案局A的标识(client-id)和密码,再附上张三出示的授权信(code),向“派出所”的“腰牌发放处”为张三申请的“腰牌”(token),将来张三可以带着这个腰牌表明身份和权限。又被重定向到“档案处”;
    (8)张三的会话(Session)已经关联上了腰牌(token),可以直接通过“档案处”查档案。

    2.1.2 张三首次访问档案局B

    张三已经成功访问了档案局A,现在他要访问档案局B。对照下图序号理解:
    (1)/(2) 同上;
    (3)张三已经有“身份证明信”,直接在“派出所”的“授权信开具处”成功开具“访问档案局B”的授权信;
    (4)/(5)/(6) 免了;
    (7)“档案局B”的“用户登记处”完成登记;
    (8)“档案局B”的“档案处”查得档案。

    2.1.3 张三再次访问档案局A

    张三已经成功访问了档案局A,现在他要访问档案局A。对照下图序号理解:
    (1)直接成功查到了档案;
    (2~8)都免了。

    2.2 HTTP 重定向原理

    HTTP 协议中,浏览器的 REQUEST 发给服务器之后,服务器如果发现该业务不属于自己管辖,会把你支派到自身服务器或其他服务器(host)的某个接口(uri)。正如我们去政府部门办事,每到一个窗口,工作人员会说“你带上材料A,到本所的X窗口,或者其他Y所的Z窗口”进行下一个手续。

    2.3 SSO 工作流程

    至此,就不难理解 OAuth 2.0 的认证/授权流程,此处不再赘述。请拿下图对照“2.1 生活实例”一节来理解。

    2.4 OAuth2.0 进阶

    根据官方标准,OAuth 2.0 共用四种授权模式:

    • Authorization Code: 用在服务端应用之间,这种最复杂,也是本文采用的模式;
    • Implicit: 用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)
    • Resource Owner Password Credentials(password): 应用直接都是受信任的(都是由一家公司开发的,本例子使用)
    • Client Credentials: 用在应用API访问。

    3 基于 SpringBoot 实现认证/授权

    官方文档:Spring Cloud Security

    3.1 授权服务器(Authorization Server)

    (1) pom.xml

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>

    (2) application.properties

    server.port=8110 ## 监听端口

    (3) AuthorizationServerApplication.java

    @EnableResourceServer // 启用资源服务器
    public class AuthorizationServerApplication {
        // ...
    }

    (4) 配置授权服务的参数

    @Configuration
    @EnableAuthorizationServer
    public class Oauth2AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
        @Override
        public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("webapp").secret("secret") //客户端 id/secret
                    .authorizedGrantTypes("authorization code") //授权妈模式
                    .scopes("user_info")
                    .autoApprove(true) //自动审批
                    .accessTokenValiditySeconds(3600); //有效期1hour
        }
    }
    
    @Configuration
    public class Oauth2WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.requestMatchers()
                    .antMatchers("/login", "/oauth/authorize/oauth/logout")
                    .and().authorizeRequests().anyRequest().authenticated()
                    .and().formLogin().permitAll();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication().withUser("admin").password("admin123").roles("ADMIN");
        }
    }

    3.2 客户端(Client, 业务网站)

    (1) pom.xml

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>

    (2) application.properties

    server port=8080
    security.oauth2.client.client-id=webapp
    security.oauth2.client.client-secret=secret
    security.oauth2.client.access-token-uri=http://localhost:8110/oauth/token
    security.oauth2.client.user-authorization-uri=http://localhost:8110/oauth/authorize
    security.oauth2.resource.user-info-uri=http://localhost:8110/oauth/user

    (3) 配置 WEB 安全

    @Configuration
    @EnableOAuth2Sso
    public class Oauth2WebsecurityConfigurer extends WebSecurityConfigurerAdapter {
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/**").authorizeRequests()
                    .antMatchers("/", "/login").permitAll()
                    .anyRequest().authenticated();
        }
    }
    
    @RestController
    public class Oauth2ClientController {
        @GetMapping("/")
        public ModelAndView index() {
            return new ModelAndView("index");
        }
    
        @GetMapping("/welcome")
        public ModelAndView welcome() {
            return new ModelAndView("welcome");
        }
    }

    3.3 用户权限控制(基于角色)

    • 授权服务器中,定义各用户拥有的角色: user=USER, admin=ADMIN/USER, root=ROOT/ADMIN/USER
    • 业务网站中(client),注解标明哪些角色可
    @RestController
    public class Oauth2ClientController {
        @GetMapping("/welcome")
        public ModelAndView welcome() {
            return new ModelAndView("welcome");
        }
    
        @GetMapping("/api/user")
        @PreAuthorize("hasAuthority('USER')")
        public Map<String, Object> apiUser() {
        }
    
        @GetMapping("/api/admin")
        @PreAuthorize("hasAuthority('ADMIN')")
        public Map<String, Object> apiAdmin() {
        }
    
        @GetMapping("/api/root")
        @PreAuthorize("hasAuthority('ROOT')")
        public Map<String, Object> apiRoot() {
        }
    }

    4 综合运用

    4.1 权限控制方案

    下图是基本的认证/授权控制方案,主要设计了认证授权服务器上相关数据表的基本定义。可对照本文“2.1 生活实例”一节来理解。

    4.2 在微服务架构中的应用

    与常规服务架构不同,在微服务架构中,Authorization Server/Resource Server 是作为微服务存在的,用户的登录可以通过API网关一次性完成,无需与无法跳转至内网的 Authorization Server 来完成。

    展开全文
  • OAuth2.0认证原理浅析

    万次阅读 多人点赞 2019-01-21 18:16:21
    OAuth目前共有2个版本,2007年12月的1.0版(之后有一个修正版1.0a)和2010年4月的2.0版,1.0版本存在严重安全漏洞,而2.0版解决了该问题,下面简单谈一下我对OAuth2.0的理解。 二.OAuth2.0有什么用?    引用...

    一.OAuth是什么?

            OAuth的英文全称是Open Authorization,它是一种开放授权协议。OAuth目前共有2个版本,2007年12月的1.0版(之后有一个修正版1.0a)和2010年4月的2.0版,1.0版本存在严重安全漏洞,而2.0版解决了该问题,下面简单谈一下我对OAuth2.0的理解。

    二.OAuth2.0有什么用?

     

             引用一下OAuth2.0中文文档中的介绍:

                1.需要第三方应用存储资源所有者的凭据,以供将来使用,通常是明文密码。

                2.需要服务器支持密码身份认证,尽管密码认证天生就有安全缺陷。

                3.第三方应用获得的资源所有者的受保护资源的访问权限过于宽泛,从而导致资源所有者失去对资源使用时限或使用范围的控制。

                4.资源所有者不能仅撤销某个第三方的访问权限而不影响其它,并且,资源所有者只有通过改变第三方的密码,才能单独撤销这第三方的访问权限。

                5.与任何第三方应用的让步导致对终端用户的密码及该密码所保护的所有数据的让步。

            简单概括,就是用于第三方在用户授权下调取平台对外开放接口获取用户相关信息。

             OAuth引入了一个授权环节来解决上述问题。第三方应用请求访问受保护资源时,资源服务器在获准资源用户授权后,会向第三方应用颁发一个访问令牌(AccessToken)。该访问令牌包含资源用户的授权访问范围、授权有效期等关键属性。第三方应用在后续资源访问过程中需要一直持有该令牌,直到用户主动结束该次授权或者令牌自动过期。

     

     

    三.OAuth2.0有哪几种授权模式?

        授权码模式(Authorization Code)(正统方式)(支持refresh token)
        授权码简化模式(Implicit)(为web浏览器设计)(不支持refresh token)
        Pwd模式(Resource Owner Password Credentials) (基本不用)(支持refresh token)
        Client模式(Client Credentials) (为后台api调用设计)(不支持refresh token)
        扩展模式(Extension)(自定义模式,这个就不介绍了)

        

       1.授权码模式(第四小结详解,此处略过)

       2.授权码简化模式

                授权访问:

                                http://localhost:8080/oauth2/oauth/authorize?     response_type=token&client_id=testid&redirect_uri=http://localhost/OAuth&scope=read


                之后接受访问,该页面将被重定向到重定向URI并带有令牌:

     

                                 http://localhost/OAuth/#access_token=KCIS89HFUE7SGE62&token_type=bearer&expires_in=3600

     

     

       3.Pwd模式

                请求格式:

                    POST -D "&grant_type=password&username=babala&password=kkk1234&scope=read,write" 

                     http://localhost/oauth/token

                服务器返回来的访问令牌:
                 {
                  "access_token":"9cd23bef-ae56-46b0-82f5-b9a8f78da569",
                  "token_type" : "bearer" ,
                  "expires_in" : 43199 ,
                  "scope" : "read"
                }

       4.Client模式

                请求格式:
    POST   -D  "&client_id=appid&grant_type=client_credentials&client_secret=appkey"  http://localhost/OAuth/token

     

                服务器返回来的访问令牌:
                {
                  "access_token":"4e56e9ec-2f8e-46b4-88b1-5d06847909ad", 
                  "token_type": "bearer” ,
                  "refresh_token":"7e14c979-7039-49d0-9c5d-854efe7f5b38",
                  "expires_in": 36133 ,
                  "scope": "read,write"
                }

     

     

    四.详解OAuth2.0的授权码简化模式?


            简单概括,就是用于第三方在用户授权下调取平台对外开放接口获取用户相关信息。

     

            有三个关键字:第三方,用户,平台,关系如下图。

     

            

            看起来很简单对吧,其实授权的部分,要比上图展示的复杂一丢丢,下面来讲解一下授权的部分。

            首先,有个问题,就拿微博平台来说吧,不能说随便一个第三方过来要求申请用户资源,微博平台就去用户那问一句是否授予权限吧,微博大哥能这么随便?所以第三方需要去想要请求的接口所在平台去报备一下,也就是告诉平台:我的xxx地址想要申请使用你的接口,可以吗?等平台审核通过之后,会下发一组appid+appkey,第三方持凭此就有资格去请求该平台的接口了。

            第三方的准备工作做好了,下面就是具体运作流程了。(各大平台大多使用授权码模式——Authorization Code,因为它相比其它几种模式更为严谨,这里我仅分析一下该模式的原理)

            这里我们假设一个场景,就是想用‘云打印’来打印自己‘微博的关注列表’。

    简图如下:

     

    详图如下:

            在第②,④,⑥,⑧步中,分别用到了云打印在微博平台上获得的appid+appkey。关于每一步请求所需要的一系列参数这里就不一一列举了,官方文档非常详细,这里仅说明一下请求code和请求access token时重要的参数。

            第④步参数:

                          response_type:指授权类型,必选,这里填固定值‘code’

                          client_id:指客户端id,必选,这里填在平台报备时获取的appid

                          redirect_uri:指重定向URI,可选

                          scope:指申请的权限范围,可选

                          state:指客户端当前状态,可选,若填了,则认证服务器会原样返回该值

     

            第⑥步参数:

                          grant_type:指使用哪种授权模式,必选,这里填固定值‘authorization_code’

                          code:指从第⑤步获取的code,必选

                          redirect_uri:指重定向URI,必选,这个值需要和第④步中的redirect_uri保持一致

     

                          client_id:指客户端id,必选,这里填在平台报备时获取的appid

     

                          client_secret:指客户端密钥,必选,这里填在平台报备时获取的appkey

     

     

            第⑧步参数:

                          access_token:指访问令牌,必选,这里填第⑦步获取的access_token

                          token_type:指令牌类型,必选,大小写不敏感,bearer类型 / mac类型

                          expires_in:指过期时间,单位秒,当其他地方已设置过期时间,此处可省略该参数

                          refresh_token:指更新令牌,可选,用即将过期token换取新token

                          scope:指权限范围,可选,第④步中若已申请过某权限,此处可省略该参数

     

    到这里,OAuth2.0 授权码模式的认证过程就完成了,原理还算比较简单,就是较为繁琐,但是不算难。

     

    注意:1.code时效较短,多为10s-10min,每次获得的code仅可使用一次,且code与client_id和redirect_uri有 一一对应关系。

              2.access token 有过期时间,多为10-15天。(过期处理有2种,请求用户重新授权/refreshToken,一般多用重新授权。)

              3.在请求时,参数中包含重定向地址的,需要和第三方在授权方平台报备时留的地址前部一致

              4.关于token_type的两种类型有什么区别,有个博客写的很详细,推荐阅读:www.cnblogs.com/XiongMaoMengNan/p/6785155.html

    此处奉上找了好久才找到的OAuth2 RFC6749中文翻译:http://colobu.com/2017/04/28/oauth2-rfc6749/

    本人能力有限,错误之处,敬请指正。

    展开全文
  • Java的oauth2.0 服务端与客户端的实现

    万次阅读 多人点赞 2017-10-02 12:33:28
    oauth原理简述 oauth本身不是技术,而是一项资源授权协议,重点是协议!Apache基金会提供了针对Java的oauth封装。...借用开涛老师一张图,就是整个oauth2.0 的协议实现原理,所有的技术层面的开发都是围绕这张图。

    oauth原理简述

    oauth本身不是技术,而是一项资源授权协议,重点是协议!Apache基金会提供了针对Java的oauth封装。我们做Java web项目想要实现oauth协议进行资源授权访问,直接使用该封装就可以。

    想深入研究原理的 可以参考:阮一峰的博客以及张开涛的博客

    借用开涛老师一张图,就是整个oauth2.0 的协议实现原理,所有的技术层面的开发都是围绕这张图。





    整个开发流程简述一下:

    1、  在客户端web项目中构造一个oauth的客户端请求对象(OAuthClientRequest),在此对象中携带客户端信息(clientId、accessTokenUrl、response_type、redirectUrl),将此信息放入http请求中,重定向到服务端。此步骤对应上图1


    2、 在服务端web项目中接受第一步传过来的request,从中获取客户端信息,可以自行验证信息的可靠性。同时构造一个oauth的code授权许可对象(OAuthAuthorizationResponseBuilder),并在其中设置授权码code,将此对象传回客户端。此步骤对应上图2


    3、 在在客户端web项目中接受第二步的请求request,从中获得code。同时构造一个oauth的客户端请求对象(OAuthClientRequest),此次在此对象中不仅要携带客户端信息(clientId、accessTokenUrl、clientSecretGrantType、redirectUrl),还要携带接受到的code。再构造一个客户端请求工具对象(oAuthClient),这个工具封装了httpclient,用此对象将这些信息以post(一定要设置成post的方式请求到服务端,目的是为了让服务端返回资源访问令牌。此步骤对应上图3。(另外oAuthClient请求服务端以后,会自行接受服务端的响应信息。


    4、 在服务端web项目中接受第三步传过来的request,从中获取客户端信息和code,并自行验证。再按照自己项目的要求生成访问令牌(accesstoken),同时构造一个oauth响应对象(OAuthASResponse),携带生成的访问指令(accesstoken),返回给第三步中客户端的oAuthClient。oAuthClient接受响应之后获取accesstoken,此步骤对应上图4


    5、 此时客户端web项目中已经有了从服务端返回过来的accesstoken,那么在客户端构造一个服务端资源请求对象(OAuthBearerClientRequest),在此对象中设置服务端资源请求URI,并携带上accesstoken。再构造一个客户端请求工具对象(oAuthClient),用此对象去服务端靠accesstoken换取资源。此步骤对应上图5


    6、 在服务端web项目中接受第五步传过来的request,从中获取accesstoken并自行验证。之后就可以将客户端请求的资源返回给客户端了。


    代码:

    客户端:

    一、pom依赖:

    <dependency>  

    <groupId>org.apache.oltu.oauth2</groupId>  

    <artifactId>org.apache.oltu.oauth2.client</artifactId>  

    <version>0.31</version>  

    </dependency> 

     


    二、controller方法:

    2.1 向服务端请求授权码code的controller方法:

    @RequestMapping("/server")

    @Controller

    public class ServerController{

      

       String clientId = null;

       String clientSecret = null;

        String accessTokenUrl = null;

        String userInfoUrl = null;

        String redirectUrl = null;

        String response_type = null;

        String code= null;

       

      

       //提交申请code的请求

       @RequestMapping("/requestServerCode")

       public String requestServerFirst(HttpServletRequestrequest, HttpServletResponseresponse, RedirectAttributesattr) throws OAuthProblemException{

          clientId = "clientId";

          clientSecret = "clientSecret";

           accessTokenUrl = "responseCode";

          redirectUrl = "http://localhost:8081/oauthclient01/server/callbackCode";

           response_type = "code";

          

          OAuthClient oAuthClient =new OAuthClient(new URLConnectionClient());

          String requestUrl = null;

          try {

            //构建oauthd的请求。设置请求服务地址(accessTokenUrl)、clientIdresponse_typeredirectUrl

            OAuthClientRequest accessTokenRequest = OAuthClientRequest

                  .authorizationLocation(accessTokenUrl)

                    .setResponseType(response_type)

                    .setClientId(clientId)

                    .setRedirectURI(redirectUrl)

                    .buildQueryMessage();

            requestUrl = accessTokenRequest.getLocationUri();

            System.out.println(requestUrl);

          } catch (OAuthSystemExceptione) {

            e.printStackTrace();

          }

          return "redirect:http://localhost:8082/oauthserver/"+requestUrl ;

       }


    此段代码对应开发步骤1.其中accessTokenUrl是服务端返回code的controller方法映射地址。redirectUrl是告诉服务端,code要传回客户端的一个controller方法,该方法的映射地址就是redirectUrl。


    2.2 向服务端请求资源访问令牌access token的controller方法:

    //接受客户端返回的code,提交申请access token的请求

       @RequestMapping("/callbackCode")

       public Object toLogin(HttpServletRequestrequest)throws OAuthProblemException{

          System.out.println("-----------客户端/callbackCode--------------------------------------------------------------------------------");

          clientId = "clientId";

          clientSecret = "clientSecret";

          accessTokenUrl="http://localhost:8082/oauthserver/responseAccessToken";

           userInfoUrl = "userInfoUrl";

           redirectUrl = "http://localhost:8081/oauthclient01/server/accessToken";

           HttpServletRequest httpRequest = (HttpServletRequest)request;

           code = httpRequest.getParameter("code");

           System.out.println(code);

           OAuthClient oAuthClient =new OAuthClient(new URLConnectionClient());

           try {

            OAuthClientRequest accessTokenRequest = OAuthClientRequest

                  .tokenLocation(accessTokenUrl)

                    .setGrantType(GrantType.AUTHORIZATION_CODE)

                    .setClientId(clientId)

                    .setClientSecret(clientSecret)

                    .setCode(code)

                    .setRedirectURI(redirectUrl)

                    .buildQueryMessage();

            //去服务端请求access token,并返回响应

            OAuthAccessTokenResponse oAuthResponse =oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);

            //获取服务端返回过来的access token

            String accessToken = oAuthResponse.getAccessToken();

            //查看access token是否过期

                Long expiresIn =oAuthResponse.getExpiresIn();

                System.out.println("客户端/callbackCode方法的token:::"+accessToken);

                System.out.println("-----------客户端/callbackCode--------------------------------------------------------------------------------");

                return"redirect:http://localhost:8081/oauthclient01/server/accessToken?accessToken="+accessToken;

          } catch (OAuthSystemExceptione) {

            e.printStackTrace();

          }

           return null;

       }


    此方法对应开发步骤3的全部和步骤4的一半,也就是还包括接受服务端返回的access token。最后的redirect地址不是服务端的地址,只是将此token传进客户端的另一个方法,该方法就是最后的资源请求方法。


    2.3 利用服务端给的token去请求服务端的资源的controller方法。这里说的资源就是服务端数据库中的user表的uname值的拼接字段。

    //接受服务端传回来的access token,由此token去请求服务端的资源(用户信息等)

       @RequestMapping("/accessToken")

       public ModelAndView accessToken(StringaccessToken) {

          System.out.println("---------客户端/accessToken----------------------------------------------------------------------------------");

          userInfoUrl = "http://localhost:8082/oauthserver/userInfo";

          System.out.println("accessToken");

          OAuthClient oAuthClient =new OAuthClient(new URLConnectionClient());

         

          try {

           

               OAuthClientRequest userInfoRequest =new OAuthBearerClientRequest(userInfoUrl)

               .setAccessToken(accessToken).buildQueryMessage();

               OAuthResourceResponse resourceResponse =oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);

               String username = resourceResponse.getBody();

               System.out.println(username);

               ModelAndView modelAndView =new ModelAndView("usernamePage");

               modelAndView.addObject("username",username);

               System.out.println("---------客户端/accessToken----------------------------------------------------------------------------------");

               returnmodelAndView;

          } catch (OAuthSystemExceptione) {

            e.printStackTrace();

          } catch (OAuthProblemExceptione) {

            e.printStackTrace();

          }

          System.out.println("---------客户端/accessToken----------------------------------------------------------------------------------");

          return null;

       }

      

    此方法对应开发步骤5的全部和步骤6的一半,也就是还包括接受服务端返回的资源信息。获取了资源信息之后,其余的开发就和平时的springmvc一毛一样了。

    以上三个方法我全部封装在同一个ServerController类中。



    服务端

     pom依赖

    1.  <dependency>  

    2.      <groupId>org.apache.oltu.oauth2</groupId>  

    3.      <artifactId>org.apache.oltu.oauth2.authzserver</artifactId>  

    4.      <version>0.31</version>  

    5.  </dependency>  

    6.  <dependency>  

    7.      <groupId>org.apache.oltu.oauth2</groupId>  

    8.      <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>  

    9.      <version>0.31</version>  

    10. </dependency> 

     



    四 controller方法

    4.1 向客户端返回授权码code的controller方法

    @Controller

    public class AuthorizeController{

      

       @Autowired

       private UserServiceuserService;

      

       //向客户端返回授权许可码 code

       @RequestMapping("/responseCode")

       public Object toShowUser(Modelmodel,  HttpServletRequestrequest){

          System.out.println("----------服务端/responseCode--------------------------------------------------------------");

         

         

             try {

             //构建OAuth授权请求 

                 OAuthAuthzRequest oauthRequest =new OAuthAuthzRequest(request);

                 /*oauthRequest.getClientId();

                 oauthRequest.getResponseType();

                 oauthRequest.getRedirectURI();

                 System.out.println(oauthRequest.getClientId());

                 System.out.println(oauthRequest.getResponseType());

                 System.out.println(oauthRequest.getRedirectURI());*/

                

             if(oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!="")

               {

               //设置授权码 

                    String authorizationCode ="authorizationCode";

                  //利用oauth授权请求设置responseType,目前仅支持CODE,另外还有TOKEN 

                    String responseType =oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);

                  //进行OAuth响应构建

                    OAuthASResponse.OAuthAuthorizationResponseBuilderbuilder =

                              OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);

                  //设置授权码

                    builder.setCode(authorizationCode);

                  //得到到客户端重定向地址

                    String redirectURI =oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);

                  //构建响应

                    final OAuthResponseresponse =builder.location(redirectURI).buildQueryMessage();

                    System.out.println("服务端/responseCode内,返回的回调路径:"+response.getLocationUri());

                    System.out.println("----------服务端/responseCode--------------------------------------------------------------");

                   String responceUri =response.getLocationUri();

                  

                  //根据OAuthResponse返回ResponseEntity响应

                      HttpHeaders headers =new HttpHeaders();

                      try {

                     headers.setLocation(new URI(response.getLocationUri()));

                  } catch (URISyntaxExceptione) {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

                  }

                      return"redirect:"+responceUri;

               }

           

          } catch (OAuthSystemExceptione) {

            e.printStackTrace();

          } catch (OAuthProblemExceptione) {

            e.printStackTrace();

          }

             System.out.println("----------服务端/responseCode--------------------------------------------------------------");

          return null;

         

         

       }

       }

    此段代码对应开发步骤2

     

    4.2 向客户端返回资源访问令牌accesstoken的controller方法

    @Controller

    public class AccessTokenController {

      

       //获取客户端的code码,向客户端返回access token

       @RequestMapping(value="/responseAccessToken",method = RequestMethod.POST

       public HttpEntity token(HttpServletRequest request){

          System.out.println("--------服务端/responseAccessToken-----------------------------------------------------------");

          OAuthIssuer oauthIssuerImpl=null;

           OAuthResponse response=null;

          //构建OAuth请求 

             try {

            OAuthTokenRequest oauthRequest =new OAuthTokenRequest(request);

            String authCode =oauthRequest.getParam(OAuth.OAUTH_CODE);

            String clientSecret = oauthRequest.getClientSecret();

            if(clientSecret!=null||clientSecret!=""){

               //生成Access Token

                   oauthIssuerImpl =new OAuthIssuerImpl(new MD5Generator());

                   final StringaccessToken =oauthIssuerImpl.accessToken();

                   System.out.println(accessToken);

                   System.out.println("--oooo---");

                 //生成OAuth响应

                   response = OAuthASResponse

                           .tokenResponse(HttpServletResponse.SC_OK)

                           .setAccessToken(accessToken)

                           .buildJSONMessage();

            }

           

               

            System.out.println("--------服务端/responseAccessToken-----------------------------------------------------------");

               

              //根据OAuthResponse生成ResponseEntity

                return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));

          } catch (OAuthSystemExceptione) {

            // TODO Auto-generated catch block

            e.printStackTrace();

          } catch (OAuthProblemExceptione) {

            // TODO Auto-generated catch block

            e.printStackTrace();

          }

            System.out.println("--------服务端/responseAccessToken-----------------------------------------------------------");

          return null;

       }

    }

     

    此段代码对应开发步骤4的前面一半,即服务端验证code、生成token并给客户端

     

    4.3 向客户端返回请求资源(username)的controller方法

    @Controller

    public class UserInfoController {

      

       @Autowired

       private UserServiceuserService;

      

       @RequestMapping("/userInfo")

       public HttpEntity userInfo(HttpServletRequest request)throws OAuthSystemException{

          System.out.println("-----------服务端/userInfo-------------------------------------------------------------");

           

          try {

             //获取客户端传来的OAuth资源请求

            OAuthAccessResourceRequest oauthRequest =new OAuthAccessResourceRequest(request, ParameterStyle.QUERY);

            //获取Access Token 

                String accessToken =oauthRequest.getAccessToken(); 

                System.out.println("accessToken");

                //验证Access Token 

                /*if (accessToken==null||accessToken=="") { 

                  // 如果不存在/过期了,返回未验证错误,需重新验证 

                OAuthResponse oauthResponse = OAuthRSResponse 

                        .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) 

                        .setError(OAuthError.ResourceResponse.INVALID_TOKEN) 

                        .buildHeaderMessage(); 

           

                  HttpHeaders headers = new HttpHeaders(); 

                  headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  

                    oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 

                return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED); 

                }  */

                //返回用户名 

                User user=userService.selectByPrimaryKey(1);

                String username = accessToken+"---"+Math.random()+"----"+user.getUname();

                System.out.println(username);

                System.out.println("服务端/userInfo::::::ppp");

                System.out.println("-----------服务端/userInfo----------------------------------------------------------");

                return new ResponseEntity(username, HttpStatus.OK)

          } catch (OAuthProblemExceptione) {

            // TODO Auto-generated catch block

            e.printStackTrace();

           

            //检查是否设置了错误码 

                String errorCode =e.getError(); 

                if (OAuthUtils.isEmpty(errorCode)) { 

                  OAuthResponse oauthResponse = OAuthRSResponse 

                         .errorResponse(HttpServletResponse.SC_UNAUTHORIZED

                         .buildHeaderMessage(); 

           

                  HttpHeaders headers =new HttpHeaders(); 

                  headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  

                    oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 

                  return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED)

                } 

           

                OAuthResponse oauthResponse = OAuthRSResponse 

                         .errorResponse(HttpServletResponse.SC_UNAUTHORIZED

                         .setError(e.getError()) 

                         .setErrorDescription(e.getDescription()) 

                         .setErrorUri(e.getUri()) 

                         .buildHeaderMessage(); 

           

                HttpHeaders headers =new HttpHeaders(); 

                headers.add(OAuth.HeaderType.WWW_AUTHENTICATE,  

                  oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); 

                System.out.println("-----------服务端/userInfo------------------------------------------------------------------------------");

                return new ResponseEntity(HttpStatus.BAD_REQUEST); 

          } 

       }

    }

     

    此代码对应开发步骤6的前一半。即服务端验证access token、并将资源信息给客户端


    至此,整个Java集成oauth就完成了。


    另外需要验证的客户端信息,如clientIdclientSecret都是自行指定,与自己的项目相关,同时客户端信息的验证方法也是依情况而定,没有什么具体标准,我的demo里为了方便,基本上省略了客户端信息验证,都是默认合法。但是accessTokenUrluserInfoUrlredirectUrl一定要与自己的项目路径相符合。response_typeGrantType有标准模板,见代码。服务端生成的access token也是有标准的,见代码,too

     

    其他的所有模块和代码就是普通的spring-springmvc-mybatis了。


    项目运行:

    项目下载地址:点击打开链接

    下载项目压缩包,解压,里面两个maven项目:oauthserver和oauthclient01,分别对应oauth服务端和客户端。

    服务端对应的数据库sql文件在源码压缩包里可以看到。

    两个项目分别用8082端口(服务端端口)和8081端口(客户端端口)部署并启动。

    输入客户端地址:http://localhost:8081/oauthclient01/index,显示如下:


    点击到服务端请求资源,就可以得到如下结果:


    即获取到了服务端的资源。




    展开全文
  • 1.架构图 技术团队通过一段时间的积累后,我们打算对往后的一些新项目采用Spring Cloud技术栈来实现。大概微服务的架构如下: ...Zuul网关集群 各模块微服务集群 Nginx实现负载均衡 Spring Cloud Config 统一配置...
  • OAuth2.0是什么

    2019-04-02 09:38:49
    介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 简单来说,上述例子中的豆瓣就是客户端,QQ就是认证服务器,OAuth2.0就是客户端和认证服务器之间由于相互不信任而产生的一个授权协议。 第一步:在豆瓣...
  • 帮你深入理解OAuth2.0协议

    万次阅读 多人点赞 2017-01-11 10:15:14
    1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间。是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题。豪车一般配备两种钥匙:主钥匙和泊车钥匙。...
  • 什么是OAuth协议 OAuth 协议为用户资源的授权提供了一个安全又简易的标准。与以往的授权方式不同之处是 OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就...
  • OAuth2.0实现第三方登录

    千次阅读 2018-12-16 18:01:01
    2、OAuth2.0是什么 3、OAuth2.0怎么写 1、引言 本篇文章是介绍OAuth2.0中最经典最常用的一种授权模式:授权码模式 非常简单的一件事情,网上一堆神乎其神的讲解,让我不得不写一篇文章来终结它们。 一项新的技术,...
  • 1.什么是OAuth2.0OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 OAuth(开放授权)是一个开放标准。允许第三方网站在用户授权的前提下访问在用户在服务商那里存储...
  • springboot2整合OAuth2.0认证实例

    万次阅读 热门讨论 2020-07-16 10:32:53
    springboot2整合OAuth2.0实例 代码实例放到:https://github.com/haoxiaoyong1014/springboot-examples springboot-oauth2 包括: springboot-oauth2-authorization-server(认证服务)和springboot-oauth2-...
  • 1. 快速实现篇(实现最基本的登录): SpringSecurity 快速实现项目 2. 企业级封装篇 我的 Spring Security 文集 SpringBoot 整合 Security(一)实现用户...SpringBoot 整合 oauth2(三)实现 token 认证 S...
  • postman着实是我这种小后台的调接口利器,今天想用它调试一个第三方平台的接口,操作记录如下文(已经注册oAuth2.0)。 获取token获取token的方法如图,token的url为第三方平台提供的通过密码获取token的url地址...
  • OAuth2.0简介(QQ登录)

    万次阅读 2014-03-14 22:48:54
    OAuth2.0简介(摘自腾讯开放平台) 目录 [隐藏] 1 1.什么是“QQ登录OAuth2.0”2 2. QQ登录OAuth2.0接入方式3 3. QQ登录OAuth2.0总体处理流程4 4. QQ登录OAuth2.0开发说明   1. 什么是“QQ登录OAuth2.0”...
  • 现在要利用security-oauth2.0去实现token验证 以免其他人随意调用,基本拦截配置已经完成了。但是token怎么生成呢?怎么去写token 的这个接口呢?本人是新手不是很熟悉,试着很多相关demo,也看了官方文档,但是还是...
  • 看别人说的是应用程序创建后生成的,看了半天都没看懂。。。。。。
  • 上图: 一般是因为没有设置微信后台参数,设置方式如下: 登陆微信后台-->开发-->接口权限-->网页授权获取用户基本信息-->修改-->填写信任域名即可
  • springboot2.0整合oauth2.0

    千次阅读 2020-04-21 16:08:06
    总结之前看了很多网上大神的实例,例子也是引用大神的,谢谢了!!! 1、在做springboot2.0和oauth2.0整合的时候(密码模式),有个问题一直想不通,请求的url中...client_id=client_2&client_secret=123456&a...
  • 验证access_token流程 OAuth2AuthenticationProcessingFilter 类 Authentication authResult = authenticationManager.authenticate(authentication); ——》OAuth2AuthenticationManager authenticate 方法 OAuth...
  • 具体就是用oauth2.0写的单点登录,我想多个系统一个登录系统,登录好了,就差退出。。。然后只要有一个系统退出所有的都退出
1 2 3 4 5 ... 20
收藏数 24,352
精华内容 9,740
关键字:

oauth2.0