关于spring-cloud-alibaba:妹子始终没搞懂OAuth20今天整合Spring-Cloud-Security-一次说明白

9次阅读

共计 10178 个字符,预计需要花费 26 分钟才能阅读完成。

大家好,我是不才陈某~

周二发了 Spring Security 系列第一篇文章,有妹子留言说看了很多文章,始终没明确OAuth2.0,这次陈某花了两天工夫,整顿了 OAuth2.0 相干的常识,联合 认证受权服务 + 资源服务,一次性给大家唠明确!

这是《Spring Security 进阶》第 2 篇文章,往期文章如下:

  • 实战!Spring Boot Security+JWT 前后端拆散架构登录认证!

本篇文章介绍一下 OAuth2.0 相干的知识点,并且手把手带大家搭建一个 认证受权核心 资源服务 进行 OAuth2.0 四种受权模式的验证,案例源码具体,一梭子带大家理解分明。

本篇文章的案例源码我的项目架构为:Spring Boot + Spring Cloud Alibaba + Spring Security,Spring Cloud Alibaba 有不理解能够看下陈某的往期《Spring Cloud 进阶》文章:

  • 五十五张图通知你微服务的灵魂摆渡者 Nacos 到底有多强?
  • openFeign 夺命连环 9 问,这谁受得了?
  • 阿里面试这样问:Nacos、Apollo、Config 配置核心如何选型?这 10 个维度通知你!
  • 阿里面试败北:5 种微服务注册核心如何选型?这几个维度通知你!
  • 阿里限流神器 Sentinel 夺命连环 17 问?
  • 比照 7 种分布式事务计划,还是偏爱阿里开源的 Seata,真香!(原理 + 实战)
  • Spring Cloud Gateway 夺命连环 10 问?
  • Spring Cloud Gateway 整合阿里 Sentinel 网关限流实战!
  • 分布式链路追踪之 Spring Cloud Sleuth 夺命连环 9 问?
  • 3 本书了,7 万 + 字,10 篇文章,《Spring Cloud 进阶》根底版 PDF

文章目录如下:

为什么须要 OAuth2.0?

编码永远都是为了解决生产中的问题,想要了解为什么须要 OAuth2,当然要从理论生存登程。

举个例子:小区的业主点了一份外卖,然而小区的门禁系统不给外卖人员进入,此时想要外卖员进入只能业主下来开门或者告知门禁的明码。

明码告知外卖员岂不是每次都能凭明码进入小区了,这显著造成了 安全隐患

那么有没有一种计划:既能不泄露明码,也能让外卖小哥进入呢?

于是此时就想到了一个受权机制,分为以下几个步骤:

  1. 门禁系统中新增一个 受权按钮,外卖小哥只须要点击受权按钮呼叫对应业主
  2. 业主收到小哥的呼叫,晓得小哥正在要求受权,于是做出了 应答受权
  3. 此时门禁系统弹出一个 明码 (相似于access_token), 有效期 30 分钟,在 30 分钟内,小哥能够凭借这个明码进入小区。
  4. 小哥输出明码进入小区

另外这个受权的明码不仅能够通过门禁,还能够通过楼下的门禁,这就十分相似于 网关 微服务 了。

令牌和明码的区别?

上述例子中令牌和明码的作用是一样的,都能够进入小区,然而存在以下几点差别:

  1. 时效不同:令牌个别都是存在过期工夫的,比方 30 分钟后生效,这个是无奈批改的,除非从新申请受权;而明码个别都是永恒的,除非客人去批改
  2. 权限不同:令牌的权限是无限的,比方上述例子中,小哥获取了令牌,可能关上小区的门禁、业主所在的楼下门禁,然而可能无奈关上其它幢的门禁;
  3. 令牌能够撤销:业主能够撤销这个令牌的受权,一旦撤销了,这个令牌也就生效了,无奈应用;然而明码个别不容许撤销。

什么是 OAuth2?

OAuth 是一个凋谢规范,该规范容许用户让第三方利用拜访该用户在某一网站上存储的私密 资源 (如头像、照片、视频等),而在这个过程中无需将 用户名 明码 提供给 第三方利用 。实现这一性能是通过提供一个令牌(token),而不是用户名和明码来拜访他们寄存在特定 服务提供者 的数据。

采纳令牌(token)的形式能够让用户灵便的对第三方利用受权或者发出权限。

OAuth2 是 OAuth 协定的下一版本,但不向下兼容 OAuth 1.0

传统的 Web 开发登录认证个别都是基于 session 的,然而在 前后端拆散 的架构中持续应用 session 就会有许多不便,因为挪动端(Android、iOS、微信小程序等)要么不反对 cookie(微信小程序),要么应用十分不便,对于这些问题,应用 OAuth2 认证都能解决。

对于大家而言,咱们在互联网利用中最常见的 OAuth2 应该就是各种第三方登录了,例如 QQ 受权登录 微信受权登录 微博受权登录 GitHub 受权登录 等等。

OAuth2.0 的四种模式?

OAuth2.0 协定一共反对 4 种不同的受权模式:

  1. 受权码模式:常见的第三方平台登录性能根本都是应用这种模式。
  2. 简化模式:简化模式是不须要客户端服务器参加,间接在浏览器中向受权服务器申请令牌(token),个别如果网站是纯动态页面则能够采纳这种形式。
  3. 明码模式:明码模式是用户把用户名明码间接通知客户端,客户端应用说这些信息向受权服务器申请令牌(token)。这须要用户对客户端高度信赖,例如客户端利用和服务提供商就是同一家公司,本人做前后端拆散登录就能够采纳这种模式。
  4. 客户端模式:客户端模式是指客户端应用本人的名义而不是用户的名义向服务提供者申请受权,严格来说,客户端模式并不能算作 OAuth 协定要解决的问题的一种解决方案,然而,对于开发者而言,在一些前后端拆散利用或者为挪动端提供的认证受权服务器上应用这种模式还是十分不便的。

1、受权码模式

这种形式是最罕用的流程,安全性也最高,它实用于那些有后端的 Web 利用。受权码通过前端传送,令牌则是贮存在后端,而且所有与资源服务器的通信都在后端实现。这样的前后端拆散,能够防止令牌透露。

令牌获取的流程如下:

上图中波及到两个角色,别离是客户端、认证核心,客户端负责拿令牌,认证核心负责发放令牌。

然而不是所有客户端都有权限申请令牌的,须要当时在认证核心申请,比方微信并不是所有网站都能间接接入,而是要去微信后盾开明这个权限。

至多要提前向认证核心申请的几个参数如下:

  1. client_id:客户端惟一 id,认证核心颁发的惟一标识
  2. client_secret:客户端的秘钥,相当于明码
  3. scope:客户端的权限
  4. redirect_uri:受权码模式应用的跳转 uri,须要当时告知认证核心。

1、申请受权码

客户端须要向认证核心拿到受权码,比方第三方登录应用微信,扫一扫登录那一步就是向微信的认证核心获取受权码。

申请的 url 如下:

/oauth/authorize?client_id=&response_type=code&scope=&redirect_uri=

上述这个 url 中携带的几个参数如下:

  • client_id:客户端的 id,这个由认证核心调配,并不是所有的客户端都能随便接入认证核心
  • response_type:固定值为code,示意要求返回受权码。
  • scope:示意要求的受权范畴,客户端的权限
  • redirect_uri:跳转的 uri,认证核心批准或者回绝受权跳转的地址,如果批准会在 uri 前面携带一个code=xxx,这就是受权码

2、返回受权码

第 1 步申请之后,认证核心会要求登录、是否批准受权,用户批准受权之后间接跳转到redirect_uri(这个须要当时在认证核心申请配置),受权码会携带在这个地址前面,如下:

http://xxxx?code=NMoj5y

上述链接中的 NMoj5y 就是受权码了。

3、申请令牌

客户端拿到受权码之后,间接携带受权码发送申请给认证核心获取令牌,申请的 url 如下:

/oauth/token?
 client_id=&
 client_secret=&
 grant_type=authorization_code&
 code=NMoj5y&
 redirect_uri=

雷同的参数同上,不同参数解析如下:

  • grant_type:受权类型,受权码固定的值为authorization_code
  • code:这个就是上一步获取的受权码

4、返回令牌

认证核心收到令牌申请之后,通过之后,会返回一段 JSON 数据,其中蕴含了令牌access_token,如下:

{    
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"read",
  "uid":100101
}

access_token则是颁发的令牌,refresh_token 是刷新令牌,一旦令牌生效则携带这个令牌进行刷新。

2、简化模式

这种模式不罕用,次要针对那些无后盾的零碎,间接通过 web 跳转受权,流程如下图:

这种形式把令牌间接传给前端,是很不平安的。因而,只能用于一些平安要求不高的场景,并且令牌的有效期必须十分短,通常就是会话期间(session)无效,浏览器关掉,令牌就生效了。

1、申请令牌

客户端间接申请令牌,申请的 url 如下:

/oauth/authorize?
  response_type=token&
  client_id=CLIENT_ID&
  redirect_uri=CALLBACK_URL&
  scope=

这个 url 正是受权码模式中获取受权码的 url,各个参数解析如下:

  • client_id:客户端的惟一 Id
  • response_type:简化模式的固定值为token
  • scope:客户端的权限
  • redirect_uri:跳转的 uri,这里前面携带的间接是 令牌,不是受权码了。

2、返回令牌

认证核心认证通过后,会跳转到redirect_uri,并且前面携带着令牌,链接如下:

https://xxxx#token=NPmdj5

#token=NPmdj5这一段前面携带的就是认证核心携带的,令牌为NPmdj5

3、明码模式

明码模式也很简略,间接通过 用户名 明码 获取令牌,流程如下:

1、申请令牌

认证核心要求客户端输出用户名、明码,认证胜利则颁发令牌,申请的 url 如下:

/oauth/token?
  grant_type=password&
  username=&
  password=&
  client_id=&
  client_secret=

参数解析如下:

  • grant_type:受权类型,明码模式固定值为 password
  • username:用户名
  • password:明码
  • client_id:客户端 id
  • client_secret:客户端的秘钥

2、返回令牌

上述认证通过,间接返回 JSON 数据,不须要跳转,如下:

{    
  "access_token":"ACCESS_TOKEN",
  "token_type":"bearer",
  "expires_in":2592000,
  "refresh_token":"REFRESH_TOKEN",
  "scope":"read",
  "uid":100101
}

access_token则是颁发的令牌,refresh_token 是刷新令牌,一旦令牌生效则携带这个令牌进行刷新。

4、客户端模式

实用于没有前端的命令行利用,即在命令行下申请令牌。

这种形式给出的令牌,是针对第三方利用的,而不是针对用户的,即有可能多个用户共享同一个令牌。

流程如下:

1、申请令牌

申请的 url 为如下:

/oauth/token?
grant_type=client_credentials&
client_id=&
client_secret=

参数解析如下:

  • grant_type:受权类型,客户端模式固定值为client_credentials
  • client_id:客户端 id
  • client_secret:客户端秘钥

2、返回令牌

认证胜利后间接返回令牌,格局为 JSON 数据,如下:

{
    "access_token": "ACCESS_TOKEN",
    "token_type": "bearer",
    "expires_in": 7200,
    "scope": "all"
}

OAuth2.0 的认证核心搭建

为了不便测试 OAuth2 的四种受权模式,这里为了不便测试,简略搭建一个认证核心,后续会逐步欠缺。

1、案例架构

陈某应用的是 Spring Boot + Spring Cloud Alibaba 作为根底搭建,新建一个oauth2-auth-server-in-memory 模块作为认证核心,目录如下:

案例源码曾经上传 GitHub,关注公众号:码猿技术专栏,回复关键词 9529 获取。

2、增加依赖

Spring Boot 和 Spring Cloud 的相干依赖这里陈某就不再说了,间接上 Spring Security 和 OAuth2 的依赖,如下:

<!--spring security 的依赖 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!--OAuth2 的依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

3、Spring Security 平安配置

这里次要波及到 Spring Security 的配置,有不分明的能够陈某第一篇文章:实战!Spring Boot Security+JWT 前后端拆散架构登录认证!

SecurityConfig这个配置类中次要设置有 4 块内容,如下:

1、加密形式

采纳 BCryptPasswordEncoder 加密,如下:

2、配置用户

这里为了不便测试,间接将用户信息存储在内存中,后续欠缺,代码如下:

上述代码配置了两个用户,如下:

  • 用户名 admin,明码 123,角色 admin
  • 用户名 user,明码 123,角色 user

3、注入认证管理器 AuthenticationManager

AuthenticationManager 明码受权模式 下会用到,这里提前注入,如果你用的不是明码模式,能够不注入,代码如下:

4、配置平安拦挡策略

因为须要验证受权码模式,因而开启表单提交模式,所有 url 都须要认证,代码如下:

4、令牌存储策略配置

令牌反对多种形式存储,比方内存形式、RedisJWT,比拟罕用的两种则是 Redis、JWT。

这里临时应用内存存储的形式,一旦服务器重启令牌将会生效。

代码如下:

5、OAuth2.0 的配置类

不是所有配置类都能够作为OAuth2.0 认证核心的配置类,须要满足以下两点:

  1. 继承AuthorizationServerConfigurerAdapter
  2. 标注 @EnableAuthorizationServer 注解

代码如下:

AuthorizationServerConfigurerAdapter须要实现的三个办法如下:

上面便是围绕这三个办法进行 OAuth2 的具体配置。

6、客户端配置

在介绍 OAuth2.0 协定的时候介绍到,并不是所有的客户端都有权限向认证核心申请令牌的,首先认证核心要晓得你是谁,你有什么资格?

因而一些必要的配置是要认证核心调配给你的,比方 客户端惟一 Id秘钥 权限

客户端配置的存储也反对多种形式,比方 内存 数据库,对应的接口为:org.springframework.security.oauth2.provider.ClientDetailsService,接口如下:

同样这里为了不便测试,仍然是加载在内存中,后续欠缺,残缺的配置如下:

几个重要参数说一下,如下:

  • .withClient("myjszl"):指定客户端惟一 ID 为 myjszl
  • .secret():指定秘钥,应用加密算法加密了,秘钥为 123
  • .resourceIds("res1"):给客户端调配的资源权限,对应的是资源服务,比方订单这个微服务就能够看成一个资源,作为客户端必定不是所有资源都能拜访。
  • authorizedGrantTypes():定义认证核心反对的受权类型,总共反对五种

    • 受权码模式:authorization_code
    • 明码模式:password
    • 客户端模式:client_credentials
    • 简化模式:implicit
    • 令牌刷新:refresh_token,这并不是 OAuth2 的模式,定义这个示意认证核心反对令牌刷新
  • scopes():定义客户端的权限,这里只是一个标识,资源服务能够依据这个权限进行鉴权。
  • autoApprove:是否须要受权,设置为 false 则不须要用户点击确认受权间接返回受权码
  • redirectUris:跳转的 uri

7、受权码服务配置

应用受权码模式必须配置一个受权码服务,用来颁布和删除受权码,当然受权码也反对多种形式存储,比方内存,数据库,这里临时应用内存形式存储,代码如下:

8、令牌服务的配置

除了令牌的存储策略须要配置,还须要配置令牌的服务 AuthorizationServerTokenServices 用来创立、获取、刷新令牌,代码如下:

9、令牌拜访端点的配置

目前这里仅仅配置了四个,别离如下:

  • 配置了受权码模式所须要的服务,AuthorizationCodeServices
  • 配置了明码模式所须要的AuthenticationManager
  • 配置了令牌治理服务,AuthorizationServerTokenServices
  • 配置 /oauth/token 申请令牌的 uri 只容许 POST 提交。

具体代码如下:

spring Security 框架默认的拜访端点有如下 6 个:

  • /oauth/authorize:获取受权码的端点
  • /oauth/token:获取令牌端点。
  • /oauth/confifirm_access:用户确认受权提交端点。
  • /oauth/error:受权服务错误信息端点。
  • /oauth/check_token:用于资源服务拜访的令牌解析端点。
  • /oauth/token_key:提供私有密匙的端点,如果你应用 JWT 令牌的话。

当然如果业务要求须要扭转这些默认的端点的 url,也是能够批改的,AuthorizationServerEndpointsConfigurer有一个办法,如下:

public AuthorizationServerEndpointsConfigurer pathMapping(String defaultPath, String customPath)

第一个参数:须要替换的默认端点 url

第二个参数:自定义的端点 url

10、令牌拜访平安束缚配置

次要对一些端点的权限进行配置,代码如下:

OAuth2.0 的资源服务搭建

客户端申请令牌的目标就是为了拜访资源,当然这个资源也是分权限的,一个令牌不是所有资源都能拜访的。

在认证核心搭建的第 6 步配置客户端详情的时候,一行代码 .resourceIds("res1") 则指定了可能拜访的资源,能够配置多个,这里的 res1 则是惟一对应一个资源。

1、案例架构

陈某应用的是 Spring Boot + Spring Cloud Alibaba 作为根底搭建,新建一个oauth2-auth-resource-in-memory 模块作为认证核心,目录如下:

案例源码曾经上传 GitHub,关注公众号:码猿技术专栏,回复关键词 9529 获取。

2、OAuth2.0 的配置类

作为资源服务的配置类必须满足两个条件,如下:

  • 标注注解@EnableResourceServer
  • 继承ResourceServerConfigurerAdapter

代码如下:

3、令牌校验服务配置

因为认证核心应用的令牌存储策略是在内存中的,因而服务端必须近程调用认证核心的校验令牌端点 /oauth/check_token 进行校验。

代码如下:

留神:近程校验令牌存在性能问题,然而后续应用 JWT 令牌则本地即可进行校验,不用近程校验了。

4、配置客户端惟一 id 和令牌校验服务

上文说到客户端有一个惟一标识,因而须要配置上,代码如下:

5、配置 security 的平安机制

上文在认证核心的第 6 步配置客户端详情那里,有一行代码 .scopes("all") 则是指定了客户端的权限,资源服务能够依据这个 scope 进行 url 的拦挡。

拦挡形式如下:

.access("#oauth2.hasScope('')")

具体配置代码如下:

这里陈某配置了所有门路都须要 all 的权限。

6、新建测试接口

新建了两个接口,如下:

  • /hello:认证胜利都能够拜访
  • /admin:只有具备 ROLE_admin 角色的用户才能够拜访

OAuth2.0 的四种模式测试

上面联合认证核心、资源服务对 OAuth2.0 的四种服务进行测试。

启动上述搭建的认证核心和资源服务,如下图:

受权码模式

1、获取受权码

申请的 url 如下:

http://localhost:2003/auth-server/oauth/authorize?client_id=myjszl&response_type=code&scope=all&redirect_uri=http://www.baidu.com

浏览器拜访,security 须要登录,如下:

输出用户名user,明码123,胜利登录。

此时来到了 确认受权 的页面,如下:

抉择 Apporove、确认受权,胜利跳转到了百度页面,并且携带了受权码,如下:

这里的 6yV2bF 就是获取到的受权码。

2、获取 token

http://localhost:2003/auth-server/oauth/token?code=jvMH5U&client_id=myjszl&client_secret=123&redirect_uri=http://www.baidu.com&grant_type=authorization_code

留神 /oauth/token 获取 token 的接口申请容许的形式要配置在受权服务器中,比方配置 POST 形式,代码如下:

.allowedTokenEndpointRequestMethods(HttpMethod.POST)

POSTMAN 申请如下图:

3、拜访资源服务

拿着令牌拜访资源服务的 /hello 接口,申请如下:

申请头须要增加 Authorization,并且值为Bearer+” “+access_token 的模式。

留神:Bearer 前面肯定要跟一个空格。

明码模式

明码模式比较简单,不必先获取受权码,间接应用 用户名 明码 获取 token。

POSTMAN 申请如下:

PS:拜访资源本人拿着获取到的令牌尝试下 …..

简化模式

简化模式就很简略了,拿着客户端 id 就能够获取 token,申请的 url 如下:

http://localhost:2003/auth-server/oauth/authorize?response_type=token&client_id=myjszl&redirect_uri=http://www.baidu.com&scope=all

这个过程和获取受权码一样,须要 登录 批准受权

最终跳转到百度,链接前面间接携带了令牌,如下:

上图中的 0d5ecf06-b255-4272-b0fa-8e51dde2ce3e 则是获取的令牌。

PS:拜访资源本人尝试下 ……….

客户端模式

申请的 url 如下:

http://localhost:2003/auth-server/oauth/token?client_id=myjszl&client_secret=123&grant_type=client_credentials

POSTMAN 申请如下:

PS:拜访资源本人尝试下 ……….

OAuth2.0 其余端点的测试

Spring Security OAuth2.0 还提供了其余的端点,上面来逐个测试一下。

1、刷新令牌

OAuth2.0 提供了令牌刷新机制,一旦 access_token 过期,客户端能够拿着 refresh_token 去申请认证核心进行令牌的续期。

申请的 url 如下:

http://localhost:2003/auth-server/oauth/token?client_id=myjszl&client_secret=123&grant_type=refresh_token&refresh_token=

POSTMAN 申请如下:

2、校验令牌

OAuth2.0 还提供了校验令牌的端点,申请的 url 如下:

http://localhost:2003/auth-server/oauth/check_token?toke=

POSTMAN 申请如下:

总结

本文介绍了 OAuth2.0 协定原理、四种受权模式,并且搭建了认证受权核心、资源服务进行了四种模式的测试。

作为 OAuth2.0 入门教程曾经十分具体了 ………..

最初说一句(别白嫖,求关注)

陈某每一篇文章都是精心输入,曾经写了 3 个专栏,整顿成PDF,获取形式如下:

  1. 《Spring Cloud 进阶》PDF:关注公号:【码猿技术专栏】回复关键词 Spring Cloud 进阶 获取!
  2. 《Spring Boot 进阶》PDF:关注公号:【码猿技术专栏】回复关键词 Spring Boot 进阶 获取!
  3. 《Mybatis 进阶》PDF:关注公号:【码猿技术专栏】回复关键词 Mybatis 进阶 获取!

如果这篇文章对你有所帮忙,或者有所启发的话,帮忙 点赞 在看 转发 珍藏,你的反对就是我坚持下去的最大能源!

正文完
 0