| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 认证与服务系列主题:微服务认证鉴权与API权限控制 -> 正文阅读 |
|
[Java知识库]认证与服务系列主题:微服务认证鉴权与API权限控制 |
目录 3-1-5. 3.1.2.2 隐式授权类型(implicit) 3-1-6. 3.1.2.3 密码模式(resource owner password credentials) 3-1-7. 3.1.2.4 客户端模式(Client Credentials) 从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断的经受考验。为了适应架构的变化、需求的变化,身份认证与鉴权方案也在不断的变革。面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证?面对外部的服务访问,该如何提供细粒度的鉴权方案? 1. 1. 背景最近在做权限相关服务的开发,在系统微服务化后,原有的单体应用是基于session的安全权限方式,不能满足现有的微服务架构的认证与鉴权需求。微服务架构下,一个应用会被拆分成若干个微应用,每个微应用都需要对访问进行鉴权,每个微应用都需要明确当前访问用户以及其权限。尤其当访问来源不只是浏览器,还包括其他服务的调用时,单体应用架构下的鉴权方式就不是特别合适了。在微服务架构下,要考虑外部应用接入的场景、用户–服务的鉴权、服务–服务的鉴权等多种鉴权场景。 2. 2. 系统架构的变更随着微服务架构的兴起,传统的单体应用场景下的身份认证和鉴权面临的挑战越来越大。单体应用体系下,应用是一个整体,一般针对所有的请求都会进行权限校验。请求一般会通过一个权限的拦截器进行权限的校验,在登录时将用户信息缓存到 session 中,后续访问则从缓存中获取用户信息。 而微服务架构下,一个应用会被拆分成若干个微应用,每个微应用都需要对访问进行鉴权,每个微应用都需要明确当前访问用户以及其权限。尤其当访问来源不只是浏览器,还包括其他服务的调用时,单体应用架构下的鉴权方式就不是特别合适了。在为服务架构下,要考虑外部应用接入的场景、用户 – 服务的鉴权、服务 – 服务的鉴权等多种鉴权场景。 David Borsos 在伦敦的微服务大会上提出了四种方案: 1. 单点登录(SSO) 2. 分布式 Session 方案 3. 客户端 Token 方案 4. 客户端 Token 与 API 网关结合 3. 3. 技术方案这主要包括两方面需求:其一是认证与鉴权,对于请求的用户身份的授权以及合法性鉴权;其二是API级别的操作权限控制,这个在第一点之后,当鉴定完用户身份合法之后,对于该用户的某个具体请求是否具有该操作执行权限进行校验。 3-1. 3.1 认证与鉴权3-1-1. 3.1.1 分布式
|
3-1-4-1. 实例
1.授权请求 比如你想用登录gitlab,想利用三方授权登录,比如谷歌账号,当你点击谷歌图标的时候,会首先发起一个授权请求。 会带上以下参数,向授权服务器发送授权请求:
response_type:表示授权类型,必选项 client_id:表示客户端的ID,必选项,一般是在授权服务器上申请应用的时候,颁发的 redirect_uri:重定向的 uri scope:表示申请的权限范围 state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回这个值
1 2 3 4 5 | response_type:表示授权类型,必选项 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
1 2 3 | 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 |
授权服务器验证该请求,确保所有的参数提交且有效,授权服务器会引导用户进入授权页面
2.当用户点击确定授权时,授权服务器会返回授权码(code)和状态参数(state),返回请求到相应的回调地址(redirect_uri)。至此,用户的主动行为已经结束。 3.第三方应用,也就是我们的客户端,在拿到授权码之后会直接向授权服务器请求访问令牌,参数如下:
grant_type:授权模式,必选项,值 "authorization_code" code:从授权服务器收到的授权码 redirect_uri:回调地址 client_id:标识应用ID client_secret:授权服务器颁发的密钥
1 2 3 4 5 | grant_type:授权模式,必选项,值??"authorization_code" code:从授权服务器收到的授权码 redirect_uri:回调地址 client_id:标识应用ID client_secret:授权服务器颁发的密钥 |
授权服务器验证通过后会返回如下参数:
1 2 3 4 5 6 7 8 9 10 11 | 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" } |
至此整个授权码流程结束。
3-1-4-2. 需要注意的几个问题
隐式授权类型(Implicit Grant Type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了”授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。流程如下:
3-1-5-1. 实例
和授权码请求一样,首先你会发起一个授权请求,验证参数
1.授权请求:
response_type:表示授权类型,此处固定值为 token client_id:客户端标识 redirect_uri:重定向 uri scope:访问的权限范围 state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回
1 2 3 4 5 | response_type:表示授权类型,此处固定值为 token client_id:客户端标识 redirect_uri:重定向 uri scope:访问的权限范围 state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回 |
客户端发起 HTTP 请求,如下:
1 2 | 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 |
2.授权服务器会验证该请求,确保所有的参数已提交且有效。授权服务器验证请求参数中的uri和客户端提交的重定向的uri保持一致。 如果,该请求是有效的,授权服务器验证对资源所有者进行身份验证并展示授权页面给用户。 用户同意授权请求时,授权服务器回返回如下参数:
access_token:授权服务器颁发的访问令牌 token_type:令牌类型 expires_in:过期时间 scope:表示授权权限范围 state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回这个
1 2 3 4 5 | access_token:授权服务器颁发的访问令牌 token_type:令牌类型 expires_in:过期时间 scope:表示授权权限范围 state:表示客户端的当前状态,可以是任意值,认证服务器会原封不动的返回这个 |
这些参数,拼接在重定向 uri 地址的后面
3.第三方应用向资源服务器发起请求,不包含上一步获取的access_token 资源服务器返回一个网页(通常是带有嵌入式脚本的 HTML 文档),其中的脚本可以提取出令牌,浏览器把access_token发送给客户端 至此整个简单授权模式结束。
隐式授权和授权码授权的区别就是,是直接获取access_token,不需要经过code步骤。但是获取的access_token需要资源服务器的脚本从第三方代理(既浏览器)中提取出来)发送给客户端。
密码模式中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向”服务商提供商”索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。流程如下:
3-1-6-1. 实例
访问令牌请求参数:
grant_type:值必须为 "password" username:资源所有者用户名 password:资源所有者密码 scope:客户端授权请求范围
1 2 3 4 | grant_type:值必须为 "password" username:资源所有者用户名 password:资源所有者密码 scope:客户端授权请求范围 |
例如:
1 2 3 4 5 | 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 |
授权服务器验证授权请求通过,参数如下:
1 2 3 4 5 6 7 8 9 10 11 | 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 框架所要解决的问题。
在这种模式中,用户直接向客户端注册,客户端以自己的名义要求”服务提供商”提供服务,其实不存在授权问题。流程如下:
3-1-7-1. 实例
访问令牌请求:
grant_type:表示授权类型,值必须为 "client_credentials" scope:客户端的授权请求反问
1 2 | grant_type:表示授权类型,值必须为 "client_credentials" scope:客户端的授权请求反问 |
如下,请求:
1 2 3 4 5 | POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials |
授权服务器验证该请求,如果请求有效则返回,令牌:
1 2 3 4 5 6 7 8 9 | 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" } |
如果,授权服务器颁发了刷新 refresh_token,可以在客户端发起刷新 access_token,一般 refresh_token有效期是大于access_token有效期 请求参数如下:
grant_type:授权类型,此处必须为 "refresh_token" refresh_token:颁发给客户端的刷新令牌 scope:表示可访问的权限范围
1 2 3 | grant_type:授权类型,此处必须为 "refresh_token" refresh_token:颁发给客户端的刷新令牌 scope:表示可访问的权限范围 |
如下 HTTP 请求
1 2 3 4 5 | 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 |
实际开发中,该模式还是需要Resource来获取userinfo或tokeninfo。
Shiro
Spring Security
正如 David Borsos 所建议的一种方案,在微服务架构下,我们更倾向于将 Oauth 和 JWT 结合使用,Oauth 一般用于第三方接入的场景,管理对外的权限,所以比较适合和 API 网关结合,针对于外部的访问进行鉴权(当然,底层 Token 标准采用 JWT 也是可以的)。
JWT 更加轻巧,在微服务之间进行访问鉴权已然足够,并且可以避免在流转过程中和身份认证服务打交道。当然,从能力实现角度来说,类似于分布式 Session 在很多场景下也是完全能满足需求,具体怎么去选择鉴权方案,还是要结合实际的需求来。
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 5:44:40- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |