mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-26 05:06:42 +08:00
761 lines
24 KiB
HTML
761 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>12 开放协议:OAuth2 协议解决的是什么问题?.md</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
|
||
|
||
|
||
<body>
|
||
|
||
|
||
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/00 开篇词 Spring Security,为你的应用安全与职业之路保驾护航.md">00 开篇词 Spring Security,为你的应用安全与职业之路保驾护航.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/01 顶级框架:Spring Security 是一款什么样的安全性框架?.md">01 顶级框架:Spring Security 是一款什么样的安全性框架?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/02 用户认证:如何使用 Spring Security 构建用户认证体系?.md">02 用户认证:如何使用 Spring Security 构建用户认证体系?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/03 认证体系:如何深入理解 Spring Security 用户认证机制?.md">03 认证体系:如何深入理解 Spring Security 用户认证机制?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/04 密码安全:Spring Security 中包含哪些加解密技术?.md">04 密码安全:Spring Security 中包含哪些加解密技术?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/05 访问授权:如何对请求的安全访问过程进行有效配置?.md">05 访问授权:如何对请求的安全访问过程进行有效配置?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/06 权限管理:如何剖析 Spring Security 的授权原理?.md">06 权限管理:如何剖析 Spring Security 的授权原理?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/07 案例实战:使用 Spring Security 基础功能保护 Web 应用.md">07 案例实战:使用 Spring Security 基础功能保护 Web 应用.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/08 管道过滤:如何基于 Spring Security 过滤器扩展安全性?.md">08 管道过滤:如何基于 Spring Security 过滤器扩展安全性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/09 攻击应对:如何实现 CSRF 保护和跨域 CORS?.md">09 攻击应对:如何实现 CSRF 保护和跨域 CORS?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/10 全局方法:如何确保方法级别的安全访问?.md">10 全局方法:如何确保方法级别的安全访问?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/11 案例实战:使用 Spring Security 高级主题保护 Web 应用.md">11 案例实战:使用 Spring Security 高级主题保护 Web 应用.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
<a class="current-tab" href="/专栏/Spring Security 详解与实操/12 开放协议:OAuth2 协议解决的是什么问题?.md">12 开放协议:OAuth2 协议解决的是什么问题?.md.html</a>
|
||
|
||
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/13 授权体系:如何构建 OAuth2 授权服务器?.md">13 授权体系:如何构建 OAuth2 授权服务器?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/14 资源保护:如何基于 OAuth2 协议配置授权过程?.md">14 资源保护:如何基于 OAuth2 协议配置授权过程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/15 令牌扩展:如何使用 JWT 实现定制化 Token?.md">15 令牌扩展:如何使用 JWT 实现定制化 Token?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/16 案例实战:基于 Spring Security 和 Spring Cloud 构建微服务安全架构.md">16 案例实战:基于 Spring Security 和 Spring Cloud 构建微服务安全架构.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/17 案例实战:基于 Spring Security 和 OAuth2 实现单点登录.md">17 案例实战:基于 Spring Security 和 OAuth2 实现单点登录.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/18 技术趋势:如何为 Spring Security 添加响应式编程特性?.md">18 技术趋势:如何为 Spring Security 添加响应式编程特性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/19 测试驱动:如何基于 Spring Security 测试系统安全性?.md">19 测试驱动:如何基于 Spring Security 测试系统安全性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/20 结束语 以终为始,Spring Security 的学习总结.md">20 结束语 以终为始,Spring Security 的学习总结.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>12 开放协议:OAuth2 协议解决的是什么问题?</h1>
|
||
|
||
<p>从今天开始,我们针对安全性的讨论将从单体服务上升到微服务架构。对于微服务架构而言,安全性设计的最核心考虑点还是<strong>认证和授权</strong>。由于一个微服务系统中各服务之间存在相互调用的关系,因此针对每一个服务,我们既需要考虑来自客户端的请求,同时也要考虑可能来自另一个服务的请求。安全访问控制就面临着从客户端请求到服务、从服务到服务的多种授权场景。因此,我们需要引入专门用于处理分布式环境下的授权体系,OAuth2 协议就是应对这种应用场景的有效解决方案。</p>
|
||
|
||
<h3>OAuth2 协议详解</h3>
|
||
|
||
<p>OAuth 是 Open Authorization 的简称,<strong>该协议解决的是授权问题</strong>而不是认证问题,目前普遍被采用的是 OAuth 2.0 版协议。OAuth2 是一个相对复杂的协议,对涉及的角色和授权模式给出了明确的定义,我们继续往下看。</p>
|
||
|
||
<h4>OAuth2 协议的应用场景</h4>
|
||
|
||
<p>在常见的电商系统中,通常会存在类似工单处理的系统,而工单的生成在使用用户基本信息的同时,势必也依赖于用户的订单记录等数据。为了降低开发成本,假设我们的整个商品订单模块并不是自己研发的,而是集成了外部的订单管理平台,此时为了生成工单记录,就必须让工单系统读取用户在订单管理平台上的订单记录。</p>
|
||
|
||
<p>在这个场景中,难点在于<strong>只有得到用户的授权</strong>,才能同意工单系统读取用户在订单管理平台上的订单记录。那么问题就来了,工单系统如何获得用户的授权呢?一般我们想到的方法是用户将自己在订单管理平台上的用户名和密码告诉工单系统,然后工单系统通过用户名和密码登录到订单管理平台并读取用户的订单记录,整个过程如下图所示:</p>
|
||
|
||
<p><img src="assets/Cgp9HWDewCGALXXGAABc1HLmoQs176.png" alt="Drawing 0.png" /></p>
|
||
|
||
<p>案例系统中用户认证和授权交互示意图</p>
|
||
|
||
<p>上图中的方案虽然可行,但显然存在几个严重的缺点:</p>
|
||
|
||
<ul>
|
||
|
||
<li>工单系统为了开展后续的服务,会保存用户在订单管理平台上的密码,这样很不安全;如果用户密码不小心被泄露了,就会导致订单管理平台上的用户数据发生泄露;</li>
|
||
|
||
<li>工单系统拥有了获取用户存储在订单管理平台上所有资料的权限,用户无法限制工单系统获得授权的范围和有效期;</li>
|
||
|
||
<li>如果用户修改了订单管理平台的密码,那么工单系统就无法正常访问订单管理平台了,这会导致业务中断,但我们又不能限制用户修改密码。</li>
|
||
|
||
</ul>
|
||
|
||
<p>既然这个方案存在如此多的问题,那么有没有更好的办法呢?答案是肯定的,<strong>OAuth2 协议</strong>的诞生就是为了解决这些问题。</p>
|
||
|
||
<p>首先,针对密码的安全性,在 OAuth2 协议中,密码还是由用户自己保管,避免了敏感信息的泄露;其次,OAuth2 协议中提供的授权具有明确的应用范围和有效期,用户可以根据需要限制工单系统所获取授权信息的作用效果;最后,如果用户对自己的密码等身份凭证信息进行了修改,只需通过 OAuth2 协议重新进行一次授权即可,不会影响到相关联的其他第三方应用程序。</p>
|
||
|
||
<p><img src="assets/CioPOWDewCqACykjAABqSG9fZc8154.png" alt="Drawing 1.png" /></p>
|
||
|
||
<p>传统认证授权机制与 OAuth2 协议的对比图</p>
|
||
|
||
<h4>OAuth2 协议的角色</h4>
|
||
|
||
<p>OAuth2 协议之所有能够具备这些优势,一个主要的原因在于它把整个系统涉及的各个角色及其职责做了很好地划分。OAuth2 协议中定义了四个核心的角色:<strong>资源、客户端、授权服务器和资源服务器</strong>。</p>
|
||
|
||
<p><img src="assets/CioPOWDewDCAIiUOAAB24Bx2cBU249.png" alt="Drawing 2.png" /></p>
|
||
|
||
<p>OAuth2 协议中的角色定义</p>
|
||
|
||
<p>我们可以把 OAuth2 中的角色与现实中的应用场景对应起来。</p>
|
||
|
||
<ul>
|
||
|
||
<li>OAuth2 协议中把需要访问的接口或服务统称为资源(Resource),每个资源都有一个拥有者(Resource Owner),也就是案例中的用户。</li>
|
||
|
||
<li>案例的工单系统代表的是一种第三方应用程序(Third-party Application),通常被称为客户端(Client)。</li>
|
||
|
||
<li>与客户端相对应的,OAuth2 协议中还存在一个服务提供商,案例中的订单管理平台就扮演了这个角色。服务提供商拥有一个<strong>资源服务器</strong>(Resource Server)和一个<strong>授权服务器</strong>(Authorization Server),其中资源服务器存放着用户资源,案例中的订单记录就是一种用户资源;而授权服务器的作用就是完成针对用户的授权流程,并最终颁发一个令牌,也就是我们所说的 Token。</li>
|
||
|
||
</ul>
|
||
|
||
<h4>OAuth2 协议的 Token</h4>
|
||
|
||
<p>看到这里,你可能会提问,所谓的访问令牌是什么?令牌是 OAuth2 协议中非常重要的一个概念,本质上也是一种<strong>代表用户身份的授权凭证</strong>,但与普通的用户名和密码信息不同,<strong>令牌具有针对资源的访问权限范围和有效期</strong>。如下所示就是一种常见的令牌信息:</p>
|
||
|
||
<pre><code>{
|
||
|
||
|
||
|
||
"access_token": "0efa61be-32ab-4351-9dga-8ab668ababae",
|
||
|
||
|
||
|
||
"token_type": "bearer",
|
||
|
||
|
||
|
||
"refresh_token": "738c42f6-79a6-457d-8d5a-f9eab0c7cc5e",
|
||
|
||
|
||
|
||
"expires_in": 43199,
|
||
|
||
|
||
|
||
"scope": "webclient"
|
||
|
||
|
||
|
||
}
|
||
|
||
</code></pre>
|
||
|
||
<p>上述令牌信息中的各个字段都很重要,我们展开分析。</p>
|
||
|
||
<ul>
|
||
|
||
<li>access_token:代表 OAuth2 的令牌,当访问每个受保护的资源时,用户都需要携带这个令牌以便进行验证。</li>
|
||
|
||
<li>token_type:代表令牌类型,OAuth2 协议中有多种可选的令牌类型,包括 Bearer 类型、MAC 类型等,这里指定的 Bearer 类型是最常见的一种类型。</li>
|
||
|
||
<li>expires_in:用于指定 access_token 的有效时间,当超过这个有效时间,access_token 将会自动失效。</li>
|
||
|
||
<li>refresh_token:其作用在于当 access_token 过期后,重新下发一个新的 access_token。</li>
|
||
|
||
<li>scope:指定了可访问的权限范围,这里指定的是访问 Web 资源的“webclient”。</li>
|
||
|
||
</ul>
|
||
|
||
<p>现在我们已经介绍完令牌,你可能会好奇这样一个令牌究竟有什么用?接下来,我们就来看如何使用令牌完成基于 OAuth2 协议的授权工作流程。整个流程如下图所示:
|
||
|
||
<img src="assets/CioPOWDewDyAFnrhAABs_ltusFE367.png" alt="Drawing 3.png" /></p>
|
||
|
||
<p>基于 OAuth2 协议的授权工作流程图</p>
|
||
|
||
<p>我们可以把上述流程进一步展开梳理。</p>
|
||
|
||
<ul>
|
||
|
||
<li>首先,客户端向用户请求授权,请求中一般包含资源的访问路径、对资源的操作类型等信息。如果用户同意授权,就会将这个授权返回给客户端。</li>
|
||
|
||
<li>现在,客户端已经获取了用户的授权信息,可以向授权服务器请求访问令牌。</li>
|
||
|
||
<li>接下来,授权服务器向客户端发放访问令牌,这样客户端就能携带访问令牌访问资源服务器上的资源。</li>
|
||
|
||
<li>最后,资源服务器获取访问令牌后会验证令牌的有效性和过期时间,并向客户端开放其需要访问的资源。</li>
|
||
|
||
</ul>
|
||
|
||
<h4>OAuth2 协议的授权模式</h4>
|
||
|
||
<p>在整个工作流程中,最为关键的是第二步,即获取用户的有效授权。那么如何获取用户授权呢?在 OAuth 2.0 中,定义了四种授权方式,即<strong>授权码模式(Authorization Code)、简化模式(Implicit)、密码模式(Password Credentials)和客户端模式(Client Credentials)</strong>。</p>
|
||
|
||
<p>我们先来看最具代表性的授权码模式。<strong>当用户同意授权后,授权服务器返回的只是一个授权码,而不是最终的访问令牌</strong>。在这种授权模式下,需要客户端携带授权码去换令牌,这就需要客户端自身具备与授权服务器进行直接交互的后台服务。</p>
|
||
|
||
<p><img src="assets/CioPOWDewEWARSNPAACJjFnruAQ327.png" alt="Drawing 4.png" /></p>
|
||
|
||
<p>授权码模式工作流程图</p>
|
||
|
||
<p>我们简单梳理一下授权码模式下的执行流程。</p>
|
||
|
||
<p>首先,用户在访问客户端时会被客户端导向授权服务器,此时用户可以选择是否给予客户端授权。一旦用户同意授权,授权服务器会调用客户端的后台服务提供的一个回调地址,并在调用过程中将一个授权码返回给客户端。客户端收到授权码后进一步向授权服务器申请令牌。最后,授权服务器核对授权码并向客户端发送访问令牌。</p>
|
||
|
||
<p>这里要注意的是,<strong>通过授权码向授权服务器申请令牌的过程是系统自动完成的,不需要用户的参与,用户需要做的就是在流程启动阶段同意授权</strong>。</p>
|
||
|
||
<p>接下来,我们再来看另一种比较常用的密码模式,其授权流程如下图所示:</p>
|
||
|
||
<p><img src="assets/Cgp9HWDewE2Ab2vhAABPDH7Zxjo001.png" alt="Drawing 5.png" /></p>
|
||
|
||
<p>密码模式工作流程图</p>
|
||
|
||
<p>可以看到,密码模式比较简单,也更加容易理解。用户要做的就是提供自己的用户名和密码,然后客户端会基于这些用户信息向授权服务器请求令牌。授权服务器成功执行用户认证操作后将会发放令牌。</p>
|
||
|
||
<p>OAuth2 中的客户端模式和简化模式因为在日常开发过程中应用得不是很多,这里就不详细介绍了。</p>
|
||
|
||
<p>你可能注意到了,虽然 OAuth2 协议解决的是授权问题,但它也应用到了认证的概念,这是因为只有验证了用户的身份凭证,我们才能完成对他的授权。所以说,<strong>OAuth2 实际上是一款技术体系比较复杂的协议,综合应用了信息摘要、签名认证等安全性手段,并需要提供令牌以及背后的公私钥管理等功能</strong>。</p>
|
||
|
||
<h3>OAuth2 协议与微服务架构</h3>
|
||
|
||
<p>对应到微服务系统中,<strong>服务提供者充当的角色就是资源服务器,而服务消费者就是客户端</strong>。所以每个服务本身既可以是客户端,也可以作为资源服务器,或者两者兼之。当客户端拿到 Token 之后,该 Token 就能在各个服务之间进行传递。如下图所示:
|
||
|
||
<img src="assets/CioPOWDewFaAKXrYAABQvvLUy-Q531.png" alt="Drawing 6.png" /></p>
|
||
|
||
<p>OAuth2 协议在服务访问场景中的应用</p>
|
||
|
||
<p>在整个 OAuth2 协议中,最关键的问题就是如何获取客户端授权。就目前主流的微服架构来说,当我们发起 HTTP 请求时,关注的是如何通过 HTTP 协议透明而高效地传递令牌,此时授权码模式下通过回调地址进行授权管理的方式就不是很实用,密码模式反而更加简洁高效。因此,在本专栏中,我们将使用<strong>密码模式</strong>作为 OAuth2 协议授权模式的默认实现方式。</p>
|
||
|
||
<h3>小结与预告</h3>
|
||
|
||
<p>今天我们进入微服务安全性领域展开了探讨,在这个领域中,认证和授权仍然是最基本的安全性控制手段。通过系统分析微服务架构中的认证和授权解决方案,我们引入了 OAuth2 协议,这也是微服务架构体系下主流的授权协议。我们对 OAuth2 协议具备的角色、授权模式以及与微服务架构之间的集成关系做了详细展开。</p>
|
||
|
||
<p>本讲内容总结如下:</p>
|
||
|
||
<p><img src="assets/CioPOWDewF2AG8SOAAGkQKcZcsU075.png" alt="Drawing 7.png" /></p>
|
||
|
||
<p>最后给你留一道思考题:你能描述 OAuth2 协议中所具备的四大角色以及四种授权模式吗?欢迎在留言区和我分享你的收获。</p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/11 案例实战:使用 Spring Security 高级主题保护 Web 应用.md">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/Spring Security 详解与实操/13 授权体系:如何构建 OAuth2 授权服务器?.md">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709975501cb43d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
|
||
|
||
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
|
||
|
||
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
|
||
|
||
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
|
||
|
||
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
</html>
|
||
|