首先,先有授权服务器(oauth2Server)、资源服务器(resourcesServer)、用户(User)
用户在授权服务器上注册账号 User,密码12345
在授权服务器上申请资源服务器的认证信息client_id=resourcesServer和client_secret=123
(另含scope和authorized_grant_types 这里不详细介绍)
(1)资源服务器生成授权URL并将用户重定向到授权服务器
(用户的操作:用户访问https://resourcesServer/index.html跳转到登录地址,选择授权服务器方式登录)
在授权开始之前,它首先生成state参数(随机字符串)。client端将需要存储这个(cookie,会话或其他方式),以便在下一步中使用。
https://oauth2Server/oauth2/default/v1/authorize?
response_type=code
&client_id=${clientId}
&redirect_uri=https://resourcesServer/authorization-code.html
&scope=授权范围
&state=随机字符串
生成的授权URL如上所述(如上),请求这个地址后重定向访问授权服务器
(2)验证授权服务器登陆状态
(用户的操作:如果未登陆用账号 User,密码12345登陆https://oauth2Server/login,如果已登陆授权服务器不需要此步骤)
如果未登陆账号,自动跳转到授权服务器登陆地址,登陆授权服务器以后用户被重定向client端
(https://resourcesServer/authorization-code.html)
如已提前登陆授权服务器或授权服务器登陆会话还存在自动重定向到client端
(https://resourcesServer/authorization-code.html)
(3)验证状态参数
(用户的操作:授权信息确认)
https://resourcesServer/authorization-code.html?state=随机字符串&code=授权码
(由于攻击者可以创建一个与此类似的GET请求,因此攻击者可以向您的应用程序提供垃圾授权代码。您需要首先验证 state参数是否与此用户的会话匹配,以便确保您启动了请求,并且只发送了一个针对您的客户机的授权代码。)
根据您存储state参数的方式(以cookie、会话或其他方式),确认它是否与步骤1中最初包含的state匹配,确认后执行下 一步
(4)交换授权码
(用户的操作:等待登陆成功或者失败信息)
这一步将授权码交换为访问令牌(access_token)了。
客户端(这步由服务器内部直接调用授权服务器)使用以下参数生成对授权服务器的POST请求:
POST https://oauth2Server/oauth2/default/v1/token
grant_type=authorization_code
&client_id=resourcesServer
&client_secret=123
&redirect_uri=https://resourcesServer/authorization-code.html
&code=授权码
响应给资源服务器令牌信息(access_token),如下所示
{ "access_token": "访问令牌", "token_type": "Bearer", "expires_in": 4200, "scope": "server", "refresh_token": "刷新令牌" }
在这之后资源服务器响应给用户,用户使用这个令牌访问资源服务器,当令牌失效时使用刷新令牌去换取新的令牌(刷新令牌有效时间大于访问令牌,刷新令牌的功能不做详细介绍)
举例QQ登陆第三方网站的流程如下图所示
前提和授权码模式一致
(1)资源服务器生成授权URL并将用户重定向到授权服务器
(用户的操作:用户访问https://resourcesServer/index.html跳转到登录地址,选择授权服务器方式登录)
在授权开始之前,它首先生成state参数(随机字符串)。client端将需要存储这个(cookie,会话或其他方式),以便在下一步中使用。
https://oauth2Server/oauth2/default/v1/authorize?
response_type=token
&client_id=${clientId}
&redirect_uri=https://resourcesServer/implicit.html
&scope=授权范围
&state=随机字符串
生成的授权URL如上所述(如上),请求这个地址后重定向访问授权服务器
(2)验证授权服务器登陆状态
(用户的操作:如果未登陆用账号 User,密码12345登陆https://oauth2Server/login,如果已登陆授权服务器不需要此步骤)
如果未登陆账号,自动跳转到授权服务器登陆地址,登陆授权服务器以后用户被重定向client端
(https://resourcesServer/implicit.html)
如已提前登陆授权服务器或授权服务器登陆会话还存在自动重定向到client端
(https://resourcesServer/implicit.html)
(3)验证状态参数
(用户的操作:无需操作)
用户被重定向回客户机,URL中现在有一个片段包含访问令牌以及一些其他信息
https://resourcesServer/authorization-code.html
#access_token=&token_type=Bearer&expires_in=3600&scope=photo&state=随机字符串
用户使用这个令牌访问资源服务器,当令牌失效时使用刷新令牌去换取新的令牌(刷新令牌有效时间大于访问令牌,刷新令牌的功能不做详细介绍)
前提和授权码模式一致,这种模式适用于鉴权服务器与资源服务器是高度相互信任的,例如两个服务都是同个团队或者同一公司开发的。
(1)验证用户名密码
(用户的操作:输入账号和密码)
POST https://oauth2Server/oauth/token
Authorization: Basic base64(resourcesServer:123)
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=User&password=12345
响应给用户令牌信息(access_token),如下所示
{
"access_token": "访问令牌",
"token_type": "Bearer",
"expires_in": 4200,
"scope": "server",
"refresh_token": "刷新令牌"
}
用户使用这个令牌访问资源服务器,当令牌失效时使用刷新令牌去换取新的令牌(刷新令牌有效时间大于访问令牌,刷新令牌的功能不做详细介绍)
仅需在授权服务器上申请资源服务器的认证信息client_id=resourcesServer和client_secret=123
这种模式一般只用在服务端与服务端之间的认证,例如OpenApi的调用
POST https://oauth2Server/oauth/token
Authorization: Basic base64(resourcesServer:123)
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
响应给用户令牌信息(access_token),如下所示
{
"access_token": "访问令牌",
"token_type": "Bearer",
"expires_in": 4200,
"scope": "server",
}
用户使用这个令牌访问资源服务器,当令牌失效时使用刷新令牌去换取新的令牌(刷新令牌有效时间大于访问令牌,刷新令牌的功能不做详细介绍)