热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

集成基于OAuth协议的单点登陆

在之前的一篇文章中,我们已经介绍了如何为一个应用添加对CAS协议的支持,进而使得我们的应用可以与所有基于CAS协议的单点登陆服务通讯。但是现在的单点登陆服务实际上并不全是通过实现CAS协议来完成的

  在之前的一篇文章中,我们已经介绍了如何为一个应用添加对CAS协议的支持,进而使得我们的应用可以与所有基于CAS协议的单点登陆服务通讯。但是现在的单点登陆服务实际上并不全是通过实现CAS协议来完成的。例如Google就使用OAuth协议来管理它的帐户。

  相较于CAS协议,OAuth协议不仅仅可以完成对用户凭证的验证,更可以提供权限管理的功能。在这些权限管理功能的支持下,一个应用甚至可以访问其它使用相同OAuth服务的应用的数据,从而完成应用间的交互。

 

OAuth集成示例

  现在我们就来看一个通过OAuth协议来访问其它应用资源的示例。

  相信您或者您的许多朋友都已经在微信中关联了LinkedIn帐号,从而可以显示相应LinkedIn帐号的一些信息。要做到这一点,我们首先需要在微信的“设置”-> “通用”-> “功能”-> “LinkedIn”下找到关联LinkedIn帐号的功能:

  在点击了关联帐号以后,我们将跳转到LinkedIn。此时LinkedIn会要求我们输入LinkedIn帐号的用户名和密码,进而允许微信访问LinkedIn帐号的部分信息:

  再跳转回到微信的时候,我们就可以看到微信已经能够访问相应的LinkedIn帐号的相关信息了:

 

 

关联流程简介

  那微信和LinkedIn之间的关联是如何建立的呢?答案就是OAuth协议。在本节中,我们将对OAuth协议的运行流程进行简单地介绍。

  注:我个人所做的工作是为Web应用添加OAuth集成。为该类型应用集成OAuth协议从流程上来说相对简单,反过来却无法较为全面地展现OAuth协议的整体运行流程。因此在本节中我们假设手机中运行的微信是一个“confidential clients”,并可以“capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection)”(RFC6749 – Section 4.1)。

  实际上,在用户点击微信中的“关联帐号”这个按钮的时候,微信可能就开始启动手机浏览器并转向下面的地址:

 

  https://{linkedin_oauth_url}/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx

 

  该URL中包含了五个较为重要的URL参数:

  • client_id。表示微信在LinkedIn中所对应的应用ID
  • redirect_uri。表示在得到了用户授权后所需要返回到的地址
  • scope。表示当前应用所申请的权限
  • response_type。表示当前应用所请求的Authorization Grant的类型
  • state。表示当前应用的状态

  一旦成功转向了该URL,那么手机浏览器将显示LinkedIn的用户登录并赋予权限的页面。如果用户成功登陆并允许微信访问这些信息,那么我们的浏览器将会被重定向到redirect_uri所标示的地址。再该地址中还会通过URL参数code来记录所得到的Authorization Grant:

 

  https://{redirect_uri}?code=AUTHORIZATION_CODE

 

  在浏览器重定向到{redirect_uri}之后,微信就知道用户已经给与了它访问当前用户的LinkedIn信息的权限,并通过URL参数code来分析出刚从OAuth服务中得到的AUTHORIZATION_CODE。接下来,微信就会通过刚刚得到的AUTHORIZATION_CODE尝试向下面的地址发送请求,以请求访问资源所需要的令牌:

 

https://{linkedin_oauth_url}/token?client_id=CLIENT_ID&code=AUTHORIZATION_CODE&grant_type=authorization_code&redirect_uri=CALLBACK_URL

 

  上面的请求中包含了四个URL参数:

  • client_id:表示微信在LinkedIn中所对应的应用ID
  • code:用来标示我们刚刚从服务端所得到的Authorization Grant
  • grant_type:用来标示Authorization Grant的类型
  • redirect_uri:用来标示成功获得令牌的情况下所需要返回的URL

  在应用成功地得到了访问资源的令牌之后,LinkedIn将返回一个包含了资源访问令牌的响应。同时浏览器将被重定向到redirect_uri所标示的位置。

  接下来,应用就可以通过刚刚获得的资源访问令牌来访问目标资源了。

  总的来说,微信(Wechat)通过OAuth协议获得用户帐号信息的流程如下所示:

 

 

OAuth协议集成

  在经过前面的示例讲解之后,相信读者们已经大概了解了OAuth协议的大致运行流程了。那么我们现在就可以开始考虑集成OAuth协议了?是的。但是在这之前,我们首先要在OAuth服务上注册应用。

  不幸的是,LinkedIn似乎没有对普通用户公开应用注册的接口。因此我们将以Digital Ocean来演示如何在一个OAuth服务上注册一个应用。

  首先,请在浏览器的地址栏中键入https://www.digitalocean.com/以来到Digital Ocean的主页面,并注册/登录。接下来,在登入的界面中点击上方的“API”,以进入应用管理页面:

  在该页面中,我们需要点击“Register New Application”来进入应用注册页面。而在该注册页面中,我们需要提供应用的一系列信息。这些信息包括:

  • 应用的名称
  • 应用的地址
  • 应用的重定向URL,即获得了Authorization Code或资源访问令牌后应用所需要重定向到的默认地址

  注册完毕以后,我们就会得到一个应用的ID以及相应的应用凭证。这一对信息用来在OAuth协议运行过程中证明应用的合法性。

  现在我们就可以开始尝试在应用中集成对OAuth协议的支持了。在OAuth协议的第一步,我们需要向OAuth服务提供者发送权限请求,以要求用户赋予访问信息的权限。就像流程简介中所讲的那样,该请求的目标URL常常包含五个参数:

  • client_id。表示应用在OAuth服务中注册时所得到的应用ID
  • redirect_uri。表示在应用得到了用户授权后所需要返回到的地址
  • scope。表示当前应用所申请的权限
  • response_type。表示当前应用所请求的Authorization Grant的类型
  • state。表示应用的当前状态。通过该参数,应用可以恢复至特定状态

  这里的五个参数都非常容易理解,但它们仍然有需要注意的地方。首先要说明的一点就是redirect_uri。它实际上是一个可选参数。在没有标明该参数的情况下,OAuth服务所返回的重定向响应就将返回到我们刚刚在应用注册时所指定的URL。只是在一般情况下,我们都会在发送权限请求的时候显式地标明该参数。这在应用使用了负载平衡,分区域部署等解决方案的情况下可以更好地对应用的性能,服务的负载等众多方面进行控制。

  接下来要说的URL参数就是scope。很不幸地,在OAuth协议中并没有规定该参数的取值范围。也就是说,不同的OAuth服务所接受的scope参数的取值范围可能并不相同。这听起来可能令人有些沮丧。但是如果OAuth协议集成框架实现得比较好的情况下,该URL参数完全可以作为框架的一个可配置的参数暴露给框架的使用者。

  最后要说的就是response_type参数。OAuth协议是一个可以在多种场景下使用的协议,如Web应用,手机应用等。它们在不同的应用场景下面对的风险和需求都各不相同,从而产生了不同的获得资源访问令牌的方法。因此您需要根据应用的实际情况选择合适的参数。而在这里,我们选择使用code,即Authorization Code Grant。因为其流程最为复杂,而且还支持资源访问令牌的刷新。

  在向OAuth服务发送了请求之后,如果浏览器能够正确地显示OAuth服务要求用户赋予权限的页面,那就表示对OAuth服务的第一步集成已经成功了。

  在正确地输入了用户名和密码,并同意应用的访问请求后,应用将接收到一个重定向响应。在接收到该响应之后,应用将记录URL参数code所标明的权限请求所得到的令牌,并使用state参数来恢复应用的状态。

  如果成功地得到权限令牌并恢复了应用状态,我们就需要开始下一步工作:通过权限令牌来得到资源访问令牌。在这一步中,我们需要像OAuth服务器发送如下形式的请求:

 

  https://{linkedin_oauth_url}/token?client_id=CLIENT_ID&code=AUTHORIZATION_CODE&grant_type=authorization_code&redirect_uri=CALLBACK_URL

 

  该请求中常常包含四个URL参数:

  • client_id:表示应用在OAuth服务中所对应的应用ID
  • code:用来标示我们刚刚从服务端所得到的权限令牌
  • grant_type:用来标示Authorization Grant的类型
  • redirect_uri:用来标示成功获得资源访问令牌的情况下所需要返回的URL

  如果请求成功地得到了服务的响应,那么我们就需要从响应中分析得到资源访问令牌access_token以及其它的一系列信息:

 

  HTTP/1.1 200 OK

  Content-Type: application/json;charset=UTF-8

  Cache-Control: no-store

  Pragma: no-cache

  {

      "access_token": "2YotnFZFEjr1zCsicMWpAA",

      "token_type": "code",

      "expires_in": 3600,

      "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",

      "example_parameter": "xxx"

  }

 

  在成功地从响应中解析出了资源访问令牌以后,我们就可以尝试着向资源服务器发送资源访问请求了。在该请求中,我们只需要将资源访问令牌作为请求的Authorization头即可。如果资源能够成功返回,那么表示我们对OAuth协议的集成已经基本成功了。

 

Refresh Token

  当然,工作还没有完全结束。在从OAuth服务器所得到的响应中还有一个较为重要的信息:refresh_token。它用来从OAuth服务那里再次获得一个资源访问令牌。这在原有的资源访问令牌过期的情况下非常有用。

  在需要通过refresh token更新资源访问令牌的时候,我们需要向OAuth服务再次发送一个获取资源访问令牌的请求。只是在该请求中,我们需要将URL参数grant_type设置为“refresh_token”,并通过URL参数refresh_token来标明之前得到的refresh_token。如果OAuth服务能够返回一个正确的响应并且能够通过该响应中包含的新的资源访问令牌访问资源服务器上的资源,那么就表示我们已经完成了对refresh token的支持。

 

Reference

OAuth协议:http://tools.ietf.org/html/rfc6749

 

转载请注明原文地址并标明转载:http://www.cnblogs.com/loveis715/p/4491456.html

商业转载请事先与我联系:silverfox715@sina.com

 

注:

  1. 本文在讲解OAuth流程时所列出的各个URL只用来作为讲解使用,而不作为任何考证依据。一切URL格式都应以相应版本协议中所定义的URL格式为准
  2. 本文在介绍微信与LinkedIn关联的图片来自于百度经验

推荐阅读
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • CRZ.im:一款极简的网址缩短服务及其安装指南
    本文介绍了一款名为CRZ.im的极简网址缩短服务,该服务采用PHP和SQLite开发,体积小巧,约10KB。本文还提供了详细的安装步骤,包括环境配置、域名解析及Nginx伪静态设置。 ... [详细]
  • 本文详细介绍了如何正确设置Shadowsocks公共代理,包括调整超时设置、检查系统限制、防止滥用及遵守DMCA法规等关键步骤。 ... [详细]
  • 在现代Web开发中,HTML5 Canvas常用于图像处理和绘图任务。本文将详细介绍如何将Canvas中的图像导出并上传至服务器,适用于拼图、图片编辑等场景。 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 理解浏览器历史记录(2)hashchange、pushState
    阅读目录1.hashchange2.pushState本文也是一篇基础文章。继上文之后,本打算去研究pushState,偶然在一些信息中发现了锚点变 ... [详细]
  • 在尝试通过自定义端口部署Spring Cloud Eureka时遇到了连接失败的问题。本文详细描述了问题的现象,并提供了有效的解决方案,以帮助遇到类似情况的开发者。 ... [详细]
  • 在Qt框架中,信号与槽机制是一种独特的组件间通信方式。本文探讨了这一机制相较于传统的C风格回调函数所具有的优势,并分析了其潜在的不足之处。 ... [详细]
  • Python Requests模块中的身份验证机制
    随着Web服务的发展,身份验证成为了确保数据安全的重要环节。本文将详细介绍如何利用Python的Requests库实现不同类型的HTTP身份验证,包括基本身份验证、摘要式身份验证以及OAuth 1认证等。 ... [详细]
  • 解决Oracle GC Agent安全配置失败的问题
    本文详细记录了在配置Oracle Grid Control (GC) Agent时遇到的安全配置失败问题及其解决方法。尽管多次尝试重启和重新配置,问题仍未完全解决,但在某些情况下,通过特定步骤可以部分恢复功能。 ... [详细]
  • CentOS7通过RealVNC实现多人使用服务器桌面
    背景:公司研发团队通过VNC登录到CentOS服务器的桌面实现软件开发工作为防止数据外泄,需要在RealVNC设置禁止传输文件、访问粘贴板等策略过程&# ... [详细]
  • 本打算教一步步实现koa-router,因为要解释的太多了,所以先简化成mini版本,从实现部分功能到阅读源码,希望能让你好理解一些。希望你之前有读过koa源码,没有的话,给你链接 ... [详细]
  • Encountering frequent mismatches during Terraform apply operations, particularly with resource attributes. ... [详细]
  • MyBatisCodeHelperPro 2.9.3 最新在线免费激活方法
    MyBatisCodeHelperPro 2.9.3 是一款强大的代码生成工具,适用于多种开发环境。本文将介绍如何在线免费激活该工具,帮助开发者提高工作效率。 ... [详细]
author-avatar
2502885590_296
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有