专栏首页复盘总结文章集合「服务器」Oauth2验证框架之项目实现

「服务器」Oauth2验证框架之项目实现

知道Oauth2验证框架工作的六个步骤:

  • (A)用户打开客户端以后,客户端要求用户给予授权。
  • (B)用户同意给予客户端授权。
  • (C)客户端使用上一步获得的授权,向认证服务器申请令牌。
  • (D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
  • (E)客户端使用令牌,向资源服务器申请获取资源。
  • (F)资源服务器确认令牌无误,同意向客户端开放资源。

那么在具体的项目中,真正是怎么实现的呢?针对这个问题,本文下面将重点介绍。

Oauth2.0是一个很通用的验证框架,很多编程语言都对其进行了实现,包括Java、PHP、Python、NodeJS、Ruby、NET、Erlang、Go、C等。大家可以在如下页面,查看自己所使用语言的实现方案。

https://oauth.net/code/

本文以PHP的实现方案为例,来讲述Oauth2在项目中的工作流程。Java、Python、NodeJS、Ruby、NET、Erlang、Go、C等语言在项目中的工作流程,大家可以对照PHP的描述,自行融会贯通。

bshaffer/oauth2-server-php是一个库,可以实现符合标准的OAuth 2.0服务器。 使用它您的用户可以对应用程序客户端进行身份验证和授权,并保护您的API。

在具体讲述bshaffer/oauth2-server-phpr的具体实现之前,我们先了解一下其中涉及到的几个重要概念:

  • 授权模式(Grant Types):授予类型允许您展示客户端接收令牌的多种方式。
  • 控制器(Controllers):OAuth服务器有3个端点,每个端点都可以由控制器进行配置。每个端点都在OAuth进程中执行不同的功能。授权端点(Authorize Endpoint):用户在这里由客户端重定向来授权请求。令牌端点(Token Endpoint) :客户端向该端点发出请求以获得访问令牌。资源端点(Resource Endpoint(s)) :客户端请求资源,为认证令牌提供访问令牌。该库支持许多不同的授权类型,包括官方OAuth规范定义的所有授权类型。
  • 存储对象(Storage Objects):该库使用存储接口来允许与多个数据层进行交互。PDO、Redis、Mongo、Cassandra、Doctrine Storage等存储类随库提供,但接口也允许您进行自定义。
  • 其他概念:Response Object、Scope、User IDs、JWT Access Tokens

授权模式(Grant Types)

bshaffer/oauth2-server-php库已经实现了OAuth 2.0授权框架RFC中定义的所有授权模式:

  1. 授权码模式(authorization code)
  2. 简化模式(implicit)
  3. 密码模式(resource owner password credentials)
  4. 客户端模式(client credentials)

控制器(Controllers)

大多数OAuth2 API将具有授权请求、令牌请求和资源请求的端点。 OAuth2 Server对象具有处理每个请求的方法。下面的每个控制器通过相同的名称对应于端点:

1、授权控制器

对于授权端点,要求用户使用授权码(授权码模式)或访问令牌(简化模式)对客户端进行认证和重定向。它有两个方法:

  • handleAuthorizeRequest
  • validateAuthorizeRequest

handleAuthorizeRequest()的作用是接收授权请求,返回授权响应。

validateAuthorizeRequest()的作用是接收授权请求,如果传入请求不是有效的授权请求,则返回false。 如果请求有效,则返回检索到的客户端详细信息和输入数组。 在向用户显示登录或授权表单之前,应用程序应该调用它。

2、资源控制器

对于任何需要oauth2身份验证的资源请求(即API调用)。 控制器将验证传入的请求,然后允许应用程序返回受保护的资源。它有两个方法:

  • verifyResourceRequest
  • getAccessTokenData

verifyResourceRequest()的作用是接收访问资源的请求,根据请求判断访问令牌(access token)是否存在,不管请求是否合法,将返回一个布尔值(true or false)。

getAccessTokenData()的作用是讲接收的请求作为参数,如果该请求有被授权返回访问令牌(access token),否则返回null。

3、令牌控制器

对于使用配置的授权类型的令牌端点,将访问令牌(access token)返回给客户端。它有两个方法:

  • grantAccessToken
  • handleTokenRequest

grantAccessToken()的作用是接收获取访问令牌(access token)的请求,如果请求有效,将返回访问令牌(access token)。

handleTokenRequest()的作用是接收获取访问令牌(access token)的请求,返回适当响应的响应对象

存储对象

该库支持多个不同存储引擎的适配器。 其中包括PDO(用于MySQL,SQLite,PostgreSQL等),MongoDB,Redis和Cassandra。这是通过多个PHP接口完成的,这个接口决定了如何存储不同的对象。 接口允许对多个平台进行扩展和定制,使得编写自己的存储类容易。存储接口还可以轻松地将对象存储在多个数据存储系统中。

下载安装

1、要求

这个库需要PHP 5.3.9+。 但是,PHP 5.2.x-5.3.8也有一个稳定的发布和开发分支。

2、下载

这个库托管在GitHub上,如果不能使用composer工具,大家也可以在如下页面下载使用:

https://github.com/bshaffer/oauth2-server-php

3、安装

这个库遵循zend PSR-0标准。 有许多自动加载器可以自动加载这个库,但是如果你不使用它,你可以手动注册OAuth2 Autoloader,如下:

如果你可以使用composer工具,可以直接使用如下命令,这个库将自动加载到你的项目中:

composer.phar require bshaffer/oauth2-server-php "^1.10"

开始使用

前面已经讲到,OAuth2 Server库已经实现了OAuth 2.0授权框架RFC中定义的所有授权模式,包括:授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)、客户端模式(client credentials)。下面我们来逐一说明。

注意:我们这里假设我们的授权服务器的域名为:

https://api.mysite.com

资源服务器的域名为:

https://myredirecturi.com

1、授权码模式(authorization code)

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

具体实现如下:

①、创建一个OAuth2 GrantType AuthorizationCode的实例并将其添加到您的服务器,如下:

②、当用户访问资源服务器时,我们将其导引到授权服务器,如下:

https://api.mysite.com/authorize?response_type=code&client_id=TestClient&redirect_uri=https://myredirecturi.com/cb

③、授权服务器验证成功后,授权服务器将传递一个授权码到资源服务器,如下:

https://myredirecturi.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

④、资源服务器利用接收到的授权码(code),调用授权服务器的接口,获取访问令牌(access token),如下:

如果调用成功,将返回如下数据:

2、简化模式(implicit)

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

具体实现如下:

①、在创建服务器时,只需配置服务器以允许简化模式。如下:

这允许授权控制器直接从请求返回访问令牌到服务器的授权端点。

②、当使用简化模式时,访问令牌将被授权控制器检索。 客户端通过在OAuth服务器的“授权”端点中设置查询字符串参数response_type = token来指定授权类型。

当用户访问资源服务器时,我们将其导引到授权服务器,如下:

https://api.mysite.com/authorize?response_type=token&client_id=TestClient&redirect_uri=https://myredirecturi.com/cb

③、授权服务器验证成功后,授权服务器将传递一个访问令牌到资源服务器,如下:

https://myredirecturi.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=bearer&expires_in=3600

3、密码模式(resource owner password credentials)

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

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

具体实现如下:

①、创建一个OAuth2 GrantType UserCredentials的实例并将其添加到您的服务器

注意:用户存储对于每个应用程序都是高度自定义的,所以强烈建议您使用OAuth2 Storage UserCredentialsInterface来实现自己的存储。

②、直接发送用户凭证来获取访问令牌

如果您的客户端是公共的(默认情况下,当客户端没有与此相关的秘钥时是这样的),则可以省略请求中的client_secret值:

③、当响应成功时,将返回访问令牌(access token),如下:

4、客户端模式(client credentials)

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

具体实现如下:

①、创建一个OAuth2 GrantType ClientCredentials的实例并将其添加到您的服务器

②、配置参数

客户端模式具有以下配置:

allow_credentials_in_request_body

除了授权HTTP头之外,是否在POST主体中查找凭证。默认值:true

③、调用接口获取访问令牌(access token)

调用成功时,返回如下数据:

补充拓展

通过上面的介绍,大家应该基本清楚了Oauth2的使用了。下面作为扩展内容,大家可以选择使用。

一、授权模式

除了上面介绍的四种模式之外,该库还是实现了另外两种模式:刷新令牌模式(Refresh Token)和JWT Bearer模式。

1、刷新令牌(Refresh Token)

刷新令牌模式用于获取额外的访问令牌,以延长客户端对用户资源的授权。

具体实现如下:

①、创建一个OAuth2 GrantType RefreshToken的实例并将其添加到您的服务器

注意:

  • 只有在使用授权码模式或密码模式检索令牌时才提供刷新令牌。
  • 如果将实现OAuth2 Storage RefreshTokenInterface的存储提供给您的OAuth2 Server实例,则只会返回刷新令牌。

②、配置参数

刷新令牌模型具有以下配置:

always_issue_new_refresh_token

是否在成功的令牌请求时发出新的刷新令牌。默认:false

访问令牌返回类型具有以下配置:

refresh_token_lifetime

刷新令牌到期之前的时间。默认:1209600(14天)

但是,当使用服务器的配置数组创建服务器时,可以发送这两个配置选项:

③、刷新令牌

使用授权码模式或密码模式检索令牌:

如果执行成功,将返回如下数据:

刷新令牌可以用来生成一个等于或小于范围的新访问令牌:

如果执行成功,将返回如下数据:

如果服务器配置为同时获取令牌和刷新令牌,那么刷新令牌也会随着此响应返回:

2、JWT Bearer

JWT Bearer模式用于客户端希望接收访问令牌而不传输敏感信息(如客户端密钥)的情况。 这也可以与受信任的客户端一起使用,以在没有用户授权的情况下访问用户资源。

具体实现如下:

①、创建OAuth2 GrantType JwtBearer的实例并将其添加到您的服务器

JWT请求需要使用公钥加密技术来签署JWT声明。 下面的代码片段提供了一个如何完成的例子。

注意:本示例使用此库中提供的OAuth2 Encryption Jwt类。 这对于JWT身份验证不是必需的,但是方便。

②、然后可以调用该函数来为请求生成负载。 编写脚本来生成jwt并请求令牌:

执行成功,将返回如下数据:

二、授权范围(scope)

在OAuth2应用程序中使用授权范围(scope)通常是正确许可的关键。 授权范围(scope)用于资源所有者限制对客户的授权。 如:Facebook用户向客户授权各种不同功能的能力(“访问基本信息”,“贴在墙上”等)。

在这个库中,授权范围(scope)是通过实现OAuth2 Storage ScopeInterface来处理的。 可以使用您自己的实现或利用现有的OAuth2 Storage Memory类来完成:

这是最简单的方法,但范围也可以动态配置:

此示例假定正在使用的类实现OAuth2 Storage ScopeInterface:

验证授权范围

在服务器类中配置授权范围(scope)将确保客户端请求的授权范围(scope)是有效的。 但是,要确保正确验证授权范围(scope),需要执行两个步骤。

首先,请求的授权范围(scope)必须在授权的情况下暴露给资源所有者。 在这个库中,这个被实现了100%。 用户界面或必须清楚授权的范围。

其次,资源请求本身必须指定访问它所需的授权范围(scope)

自定义授权范围

由于每个应用程序的授权范围(scope)的实现可能会有很大差异,因此提供除OAuth2 Scope以外的其他类别可能会有所帮助。 在自定义类中实现OAuth2 ScopeInterface以完全自定义。

state状态参数默认是授权重定向所必需的。 这相当于一个CSRF令牌,并为您的授权请求提供会话验证。 这是为了安全目的而默认启用的,但是当你配置你的服务器时你可以删除这个需求

使用多个范围

您可以通过在授权请求中提供以空格分隔(但是网址安全)的作用域列表来请求多个作用域。 它看起来像这样:

这将创建一个具有以下四个范围的授权代码:“onescope”,“twoscope”,“redscope”和“bluescope”,然后使用OAuth2 ScopeUtil类对这些范围进行验证,以确保它们存在。 如果您收到错误invalid_scope:请求不支持的作用域,这是因为您需要在服务器对象上设置可用的作用域,如下所示:

限制客户端访问范围

客户端可用的范围由客户端存储中的作用域字段和作用域存储中定义的可用作用域列表的组合来控制。当客户端有一个配置的范围列表时,客户端被限制为仅使用那些范围。 当没有配置范围时,客户端可以使用的范围不受限制,它可以使用授权服务器内可用的所有范围。

三、User IDs

将本地用户与访问令牌相关联

一旦你对一个用户进行了认证并发布了一个访问令牌(比如一个授权控制器),那么你可能想知道当访问令牌被使用时哪个用户被应用。您可以通过使用handleAuthorizeRequest的可选user_id参数来执行此操作:

这将使用访问令牌将用户标识保存到数据库中。 当令牌被客户端使用时,您可以检索关联的ID:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【JeeSite】角色和权限的修改(二次开发代码解析)

    页面传参数menuIds , 数据库保存用的参数是menuList, 中间通过setMenuIds--->setMenuIdList---->menuList

    ZhangXianSheng
  • 利用php url转发 - 解决空间不提供子目录绑定功能的问题

    由于很多新手都是使用的虚拟空间都是最便宜的那种,这空间一般不支持子目录绑定。但是很多朋友又想设置几个不同的二级域名访问不同的网站程序。于是大家找到了域名url转...

    ZhangXianSheng
  • Elasticsearch 基本命令

    Elasticsearch 命令的一般格式是:REST VERBHOST:9200/index/doc-type— 其中 REST VERB 是 PUT、GET...

    ZhangXianSheng
  • OAuth2.0授权协议

    通过用户授权,第三方服务访问用户存在其他服务上的资源,而不需用户将用户名密码直接传递的资源服务器的安全控制协议。

    sucl
  • 微服务统一认证与授权的 Go 语言实现(上)

    最近疫情严重,是一个特殊时期,大家一定要注意防护。很多省份推迟了企业开工的时间,大部分的互联网公司也都是下周开始远程办公。大家可以利用在家的几天时间学习充电,反...

    aoho求索
  • OAuth 2.0初学者指南

    本文概述了OAuth 2.0协议。它讨论了OAuth 2.0实现过程中涉及的不同参与者和步骤。

    银河1号
  • 深入理解RPC之序列化篇--Kryo

    一年前,笔者刚刚接触RPC框架,从单体式应用向分布式应用的变革无疑是让人兴奋的,同时也对RPC背后到底做了哪些工作产生了兴趣,但其底层的设计对新手而言并不是很...

    kirito-moe
  • Android平台下的第一个Tor木马

    作者 Taskkiller 通常来说,Android木马作者一般都是以Windows下的恶意软件功能作为模板对Android木马进行功能开发。近期,另一个Win...

    FB客服
  • RPC(3)

    RPC(Remote Procedure Call)是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是...

    桑鱼
  • 微服务框架saf-1:容器化部署allinone-demo

    3.解放业务,使业务方专注于业务逻辑本身:通过注解以搭积木方式引入各式资源,每个资源都是一行注解,极大提升业务方产出效率。

    千里行走

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动