Oauth2.0四种授权模式适用场景和授权流程介绍以及个人的一些思考

这篇具有很好参考价值的文章主要介绍了Oauth2.0四种授权模式适用场景和授权流程介绍以及个人的一些思考。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Oauth 协议为用户资源的授权提供了一个安全的、开放而又简易的标准,先前曾经了解过在 spring-security-oauth2Oauth 四种模式的实现,也通过 Shiro 实现了 Oauth 的授权流程。

目前 spring-security-oauth2 已经被逐步废弃,Spring 也提供了新的框架 spring-authorization-server,整个框架基于 Oauth 2.1 开发。目前重新整理项目代码,借此机会详细梳理一遍 Oauth2.0 授权模式的适用场景和授权流程,后续用于和 2.1 对比参照。

一、四种授权模式

1.1 客户端凭证模式

该模式针对客户端而言,对用户是透明的,不需要用户参与,非用户层面授权。客户端向授权服务器发送自己的的 client_idclient_secrect 请求 access_token ,用户中心仅校验客户端应用身份 。客户端通过授权后可以获得授权范围内所有用户的信息,对客户端应用需要极高的信任。

模式特点: 针对客户端层面进行授权,而非对单独用户进行授权的场景,用户中心仅校验客户端应用的身份。

适用场景: 适用于的自家产品、微服务中,需要从接口层面发起请求的场景。

当前模式仅生成 access_token,不生成 refresh_token

1.2 密码模式

用户直接提供用户名与密码给客户端应用,客户端使用用户的账号和密码、自己的 client_idclient_secrect 向授权服务器请求 token 。用户中心校验用户和客户端应用身份,响应 access_tokenrefresh_token

模式特点: 用户的账号和密码直接暴露给客户端,安全性低。

适用场景: 适用于自家的产品、微服务中,需要从用户层面发起请求的场景。

该模式已经被 Oauth2.1 废弃,直接将用户的账号和密码明文交给客户端应用是一个传统的方案,其本身没有校验意义,需要逐步过渡到通过 token 凭证这种授权方式。

换而言之,客户端都有密码了,通过 Oauth2.0 流程要一个临时的 access_token 干嘛?

1.3 授权码模式

客户端应用引导用户携带着 client_idredirect_url 前往认证服务器认证,认证通过后认证服务会附带上 code 参数重定向到 redirect_url 地址(客户端应用提供的接收授权码的地址)。客户端应用的服务端携带自己的 client_idclient_secrectcode 请求认证服务器获取 access_tokenrefresh_token 返回到用户。

模式特点: 四种模式中最安全、最常见的一种模式。

适用场景: 适用于有服务端服务的客户端应用。

网上说,这种方式避免了 access_token 直接在公网传输,黑客截获到 code 也无法获得最终的 access_token,所以这种方案非常安全。

不是非常认同,如果 code 会被截获,那么用户登录时的 token 是否也可以直接被截获到?Oauthtoken 是否在公网在公网上传输已经不重要了,因为用户登录的 token 已经在公网上传输了。

个人观点认为,安全主要体现在这种模式同时校验了用户和客户端应用的 client_secrect ,与密码模式不同,当前模式用户和客户端应用双方都不知道对方的密码明文。

1.4 隐式授权(简易模式)

客户端应用引导用户携带 client_id 前往授权服务器认证,认证通过后认证服务器直接返回 access_token

模式特点: 不需要与客户端应用的服务端进行交互,没有校验 client_secrect

适用场景: 适用于仅有前端页面,没有后端服务的客户端应用。

通过 # 锚点链接的方式返回 access_token,避免 token 被携带传输到 web 前端文件托管的服务器上。

该模式已经被 Oauth2.1 废弃,这种方式容易泄露 token ,不安全。

二、授权流程

2.1 客户端凭证模式

授权流程:

客户端启动时向授权服务器的 POST /oauth/token 接口发起获取 access_token 的请求,在 access_token 即将过期时再次请求重新获取 access_token

参数名 必填 说明
grant_type 客户端凭证模式填 client_credentials
client_id 客户端ID
client_secret 客户端秘钥
scopes 指定授权范围,多个权限用 , 分隔,默认为客户端可申请的所有权限

请求示例:

通过客户端应用的 ID 和 Secret 获取 access_token ,该 access_token 具有对所有用户的权限:

curl --location --request POST 'http://127.0.0.1:4540/oauth/token?grant_type=client_credentials&client_id=gongyi&client_secret=32c21505c0d0422c99fd158d0eaa5880&scopes=USER_INFO,GET_SECURITY'

>>> 获取token
{
    "error": false,
    "code": 200,
    "data": {
        "scopes": [
            "USER_INFO",
            "GET_SECURITY"
        ],
        "access_token": "59f117422bf945d5a021e4911312a602",
        "expires_in": 43200
    }
}

2.2 密码模式

授权流程:

  1. 客户端提供一个登录接口,直接接收用户的登录账号和密码。

  2. 客户端应用的服务端接收到用户的账号和密码,向授权服务器的 POST /oauth/token 接口发起获取 access_tokenrefresh_token 的请求,并传入如下几个参数:

    参数名 必填 说明
    grant_type 密码模式填 password
    client_id 客户端ID
    client_secret 客户端秘钥
    username 用户登录账号
    password 用户登录密码
    scopes 指定授权范围,多个权限用 , 分隔,默认为客户端可申请的所有权限

    授权服务器将 access_tokenrefresh_token 响应给客户端应用的服务端。

请求示例:

通过用户的账号密码和客户端应用的 ID 和 Secret 获取 token

curl --location --request POST 'http://127.0.0.1:4540/oauth/token?grant_type=password&username=12312312312&password=123123&client_id=gongyi&client_secret=32c21505c0d0422c99fd158d0eaa5880&scopes=USER_INFO,GET_SECURITY'

>>> 获取token
{
    "error": false,
    "code": 200,
    "data": {
        "scopes": [
            "USER_INFO",
            "GET_SECURITY"
        ],
        "access_token": "4df53c0d1a4446e28fe55e281b5b6693",
        "expires_in": 43200,
        "refresh_token": "3f447d939fcc41db907551052a96950f"
    }
}

2.3 授权码模式

授权流程:

  1. 打开授权页面 GET /oauth/authorize,并传入如下几个参数:

    参数名 必填 说明
    response_type 授权码模式填 code
    client_id 客户端ID
    redirect_uri 授权通过后重定向跳转的URL
    scopes 指定授权范围,多个权限用 , 分隔,默认为客户端可申请的所有权限
    state 请求状态,用于防重放
  2. 用户进行登录 POST /api/public/user/login,认证用户身份。

  3. (用户无须操作,登录即授权)前端接受到登录成功的响应,自动请求授权接口 POST /oauth/authorize,并传入如下几个参数:

    不需要再传 response_typeclient_id 这些信息了,这些信息已经通过 session 关联。

    参数名 必填 说明
    user_oauth_approval 用户是否通过授权填 true
    scope.{权限名} true 为指定权限通过授权

    请求通过后,将携带生成的 code 和打开授权界面时传送的 state 参数,跳转到 redirect_uri 地址。

  4. 客户端应用的服务端接收到请求,向授权服务器的 POST /oauth/token 接口发起请求获取 access_tokenrefresh_token 的请求,并传入如下几个参数:

    参数名 必填 说明
    grant_type 授权码模式填 authorization_code
    code 授权码
    client_id 客户端ID
    client_secret 客户端秘钥

    最后授权服务器将 access_tokenrefresh_token 响应给客户端应用的服务端。

请求示例:

  1. 打开授权界面

    curl --location --request GET 'http://127.0.0.1:4540/oauth/authorize?response_type=code&client_id=gongyi&redirect_uri=https://blog.nineya.com/&scopes=USER_INFO,GET_SECURITY&state=123'
    
    >>> 授权界面html
    
  2. 发起获取授权码的请求

    curl --location --request POST 'http://127.0.0.1:4540/oauth/authorize?user_oauth_approval=true&scope.USER_INFO=true' \
    --header 'User-Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjE2NzE0NTcxNjg4OTU3MzMsImlzcyI6IlVTRVIiLCJpYXQiOjE2NzE1NDMwMzd9.b4q7qn0t_LOX84P5Huf9sV1XFNLyIp972hdL7ng4m4o'
    
    >>> 得到的授权码为x24lgN
    {
        "error": false,
        "code": 200,
        "data": "https://blog.nineya.com/?code=x24lgN&state=123"
    }
    
  3. 获取 access_tokenrefresh_token

    curl --location --request POST 'http://127.0.0.1:4540/oauth/token?grant_type=authorization_code&code=x24lgN&client_id=gongyi&client_secret=32c21505c0d0422c99fd158d0eaa5880'
    
    >>> 获取token
    {
        "error": false,
        "code": 200,
        "data": {
            "scopes": [
                "USER_INFO"
            ],
            "access_token": "b8ee3da722794fb0b1c9f236de7f33a9",
            "expires_in": 43200,
            "refresh_token": "f676fdd4bbe34e2d8ac195a00b8f3fa9"
        }
    }
    

2.4 隐式授权(简易模式)

授权流程:

  1. 打开授权页面 GET /oauth/authorize,并传入如下几个参数:

    参数名 必填 说明
    response_type token 模式填 token
    client_id 客户端ID
    redirect_uri 授权通过后重定向跳转的URL
    scopes 指定授权范围,多个权限用 , 分隔,默认为客户端可申请的所有权限
    state 请求状态,用于防重放
  2. 用户进行登录 POST /api/public/user/login,认证用户身份。

  3. (用户无须操作,登录即授权)前端接受到登录成功的响应,自动请求授权接口 POST /oauth/authorize,并传入如下几个参数:

    不需要再传 response_typeclient_id 这些信息了,这些信息已经通过 session 关联。

    参数名 必填 说明
    state 请求状态,用于防重放
    access_token 获取的 token
    expires_in token 失效时间
    scopes 获取的权限列表

    请求通过后,将携带生成的 token 相关信息作为锚点参数(不生成 refresh_token),将打开授权界面时传送的 state 作为参数,跳转到 redirect_uri 地址。

请求示例:

  1. 打开授权界面

    curl --location --request GET 'http://127.0.0.1:4540/oauth/authorize?response_type=code&client_id=gongyi&redirect_uri=https://blog.nineya.com/&scopes=USER_INFO,GET_SECURITY&state=123'
    
    >>> 授权界面html
    
  2. 获取 access_token

    curl --location --request POST 'http://127.0.0.1:4540/oauth/authorize?user_oauth_approval=true&scope.USER_INFO=true' \
    --header 'User-Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjE2NzE0NTcxNjg4OTU3MzMsImlzcyI6IlVTRVIiLCJpYXQiOjE2NzE1NDMwMzd9.b4q7qn0t_LOX84P5Huf9sV1XFNLyIp972hdL7ng4m4o'
    
    >>> 通过锚点参数响应access_token
    {
        "error": false,
        "code": 200,
        "data": "https://blog.nineya.com/?state=123#access_token=6fea088dfbb54c1da370ebe6b8e6ccf7&expires_in=43200&scopes=USER_INFO"
    }
    

2.5 刷新 token

access_token 即将过期时,调用 POST /oauth/token,并传入如下几个参数进行 access_token 刷新。

参数名 必填 说明
grant_type 刷新 tokenrefresh_token
client_id 客户端ID
client_secret 客户端秘钥
refresh_token refresh_token

如果刷新成功,则响应新的 access_tokenrefresh_token,原 access_tokenrefresh_token 失效。

2.6 校验 token

调用 GET/oauth/check_token,并通过 token 参数传入 access_token 进行校验,校验通过返回用户id、客户端 ID 和授权范围信息。

curl --location --request GET 'http://127.0.0.1:4540/oauth/check_token?token=70b5e4c4084843f2babe1c3146b1f088'

>>>
{
    "error": false,
    "code": 200,
    "data": {
        "uid": -1,
        "clientId": "gongyi",
        "scopes": [
            "USER_INFO",
            "GET_SECURITY"
        ]
    }
}

三、Oauth授权的思考

本文的四种授权模式的实现基本上参考于 spring-cloud-starter-oauth2:2.2.4,但是一些授权细节上有调整,具体如下:

  1. 允许用户未登录就打开授权界面,在授权界面中可一键登录并授权(参考的 QQ 的授权界面);
  2. 允许设置必选权限、可选权限(也是参考的QQ的授权界面);
  3. 将获取授权码和 token 时的跳转改为响应跳转 url,在 JavaScript 中进行跳转;
  4. 也许还有其他一些细微的调整?忘了。

3.1 凭证模式与密码模式的意义

目前,在使用中还未实际用到客户端凭证模式和密码模式,仅仅是一个思考。

对于内部产品:

现在流行的是微服务架构,我们将产品都集成在了同一个微服务集群中,这样做方便管理,也方便通过 feign 进行服务间互访。

微服务间调用单独的开放一套接口,这些接口对公网的访问屏蔽,对微服务的调用请求没有进行任何权限校验。因为已经集成在同一个微服务集群上的应用之间本身就具有极高的信任程度,一般还是在同一个局域网之中,所以通过客户端凭证的方式进行校验失去了意义。

对于不可信的产品:

外部的可行度较低的服务通过凭证模式接入是一个比较个人推崇的方案,客户端凭证再辅加网络白名单策略或代理策略个人认为完全能保证通信的安全。但是这有一个前提,就是该应用允许具有对该接口完全的访问权限,否则就还需要在接口中额外的开发对客户端应用的身份和访问权限进行校验的逻辑。而密码模式,让客户端应用直接存储用户的账户和密码明文,这种方式是不建议的。

在授权框架层面上,是否能有一种只开放指定数据访问权限,且不需要用户显式操作登录的方案?

3.2 用户授权的方式

除了客户端凭证授权方式,另外三种授权方式用户都参与到了授权流程中。

spring-security-oauth2 的实现上看,其中授权码模式和隐式授权模式都和应用前端和 session 具有强关联关系,主要体现在:

  1. 通过 session 判断当前用户是否打开过授权界面,如果未打开过则不允许访问授权接口;
  2. 获取授权码或 token 后使用了链接跳转和重定向功能。

这样会存在一些问题,session 的方案不适合微服务的架构,除非只部署一个 Oauth 认证服务器,授权流程依赖于那个前端,对于 App 、小程序或者 Vue 单页面应用这类场景,需要再进行适配。

3.3 关于 JWT

Oauth 中,token 是由授权服务器颁发,访问资源服务器的数据的模式,资源服务器需要前往授权服务器校验 token 的有效性,也就是需要调用 GET/oauth/check_token 接口。

JWT 是一种将用户可公开的部分数据存放在 token 中的方案,对用户数据进行签名,将签名算法、用户数据和签名后的密文共同组成 tokentoken 中的用户数据明文可读。

如果采用 JWT 来做 token,那么资源服务器无须前往授权服务器校验也可知道 token 的有效性,这将提高资源访问的效率。

但这要建立在一个前提上,颁发出去的 token 不能提前失效,因为资源服务器仅靠 token 校验有效性。如果用户的 token 泄露了就无法阻止非法用户访问数据,所以 token 有效期需要尽量短。在授权服务器应可以禁用某个用户或者 token 避免非法用户使用 refresh_token 刷新更换新的 token

可以和客户端协定一个 Jwt 签名公私钥,如果有大量用户的 token 泄露则更换签名公私钥。

本文采用 UUID 作为 token,状态数据存储在 redis 上,如果需要 token 提前过期,删除 redis 中对应的缓存即可。文章来源地址https://www.toymoban.com/news/detail-775849.html

到了这里,关于Oauth2.0四种授权模式适用场景和授权流程介绍以及个人的一些思考的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot整合springsecurity+oauth2.0密码授权模式

    本文采用的springboot去整合springsecurity,采用oauth2.0授权认证,使用jwt对token增强。本文仅为学习记录,如有不足多谢提出。 OAuth 2.0是用于授权的行业标准协议。OAuth 2.0为简化客户端开发提供了特定的授权流,包括Web应用、桌面应用、移动端应用等。 Resource owner(资源拥有者)

    2024年02月04日
    浏览(61)
  • 自定义OAuth2组件实现对授权码登录模式的封装

    所谓OAuth2其实就是Open Authorization,即开放授权,是一种授权机制或者说是一种协议。 OAuth2允许用户授权第三方应用访问其存储在开放平台(授权服务器)中的数据而不需要提供密码 。授权服务器根据OAuth2协议标准制订一套授权的API,第三方网站接入开放平台之后即可通过其

    2024年02月05日
    浏览(38)
  • oauth2-resource-server授权配置介绍

    当了解这篇文章授权服务器后,对授权服务器有一定的认识,那么授权服务器生成token后,该怎么用呢,这就涉及到资源服务器,现在给大家简单介绍实现过程。 2.1 基于官网配置 首先先配置 issuer-uri ,这里指向是授权服务器的地址 关于过滤器链的配置: 资源服务器将使用

    2024年02月12日
    浏览(31)
  • 【安全】 阅读 RFC6749 及理解 Oauth2.0 下的授权码模式

    OAuth 2.0 规范来自 RFC6749。看了《Spring 微服务实战》对OAuth 2.0 的介绍后还是觉得存在一些翻译的问题。现在结合 RFC6749 一起重新梳理下。 1.1. 一个场景: o-stock 实现获取微信头像。 结论性的东西全部来自于该文档。 本文是主要以获取微信头像作为模型,对 Oauth2.0 知识点进行

    2024年02月11日
    浏览(43)
  • 授权码 + PKCE 模式|OIDC & OAuth2.0 认证协议最佳实践系列【03】

    ​ 在上一篇文章中,我们介绍了 OIDC 授权码模式(点击下方链接查看), 本次我们将重点围绕 授权码 + PKCE 模式(Authorization Code With PKCE)进行介绍 ,从而让你的系统快速具备接入用户认证的标准体系。 OIDC OAuth2.0 认证协议最佳实践系列 02 - 授权码模式(Authorization Code)接

    2024年02月01日
    浏览(92)
  • 图解OAuth 2.0授权模式及应用场景

    本文深入剖析了OAuth 2.0与OAuth的区别,详细介绍了OAuth 2.0的认证流程、安全性和应用场景,以及OAuth 2.0的四种常见授权类型:授权码模式、简化模式、密码模式和客户端凭证模式。

    2024年04月14日
    浏览(55)
  • 【springboot+vue项目(十四)】基于Oauth2的SSO单点登录(一)整体流程介绍

    场景:现在有一个前后端分离的系统,前端框架使用vue-element-template,后端框架使用springboot+springSecurity+JWT+Redis(登录部分)现在需要接入到 已经存在的第三方基于oauth2.0的非标准接口 统一认证系统。  温馨提示:如果是接入到 基于oauth2.0的 标准接口的认证服务系统,可以直

    2024年02月19日
    浏览(44)
  • SpringBoot 如何使用 OAuth2 进行认证和授权

    OAuth2 是一种授权框架,可以用于实现第三方应用程序访问用户资源的安全性。在 SpringBoot 中,我们可以使用 Spring Security 和 Spring OAuth2 来实现 OAuth2 的认证和授权功能。本文将介绍如何在 SpringBoot 中使用 OAuth2 进行认证和授权。 在开始介绍如何使用 OAuth2 进行认证和授权之前,

    2024年02月13日
    浏览(35)
  • Spring OAuth2 授权服务器配置详解

    首先要创建一个Spring Boot Servlet Web项目,这个不难就不赘述了。集成 Spring Authorization Server 需要引入: OAuth2.0 Client 客户端需要注册到授权服务器并持久化, Spring Authorization Server 提供了 JDBC 实现,参见 JdbcRegisteredClientRepository 。为了演示方便这里我采用了H2数据库,需要以下依

    2024年04月13日
    浏览(45)
  • 搭建spring security oauth2认证授权服务器

    下面是在spring security项目的基础上搭建spring security oauth2认证授权服务器 spring security oauth2认证授权服务器主要需要以下依赖 Spring Security对OAuth2默认可访问端点 ​/oauth/authorize​ ​​:申请授权码code,涉及类​ ​AuthorizationEndpoint​ ​ ​/oauth/token​ ​​:获取令牌token,涉及类​

    2024年01月21日
    浏览(57)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包