SpringCloudAlibaba整合Oauth2,博⽂有点长耐⼼看完不说精
通,⾄少从零。。。
SpringCloudOauth2
Oauth2简介
OAuth 2.0是⽤于授权的⾏业标准协议。OAuth 2.0致⼒于简化客户端开发⼈员,同时为Web应⽤程序,桌⾯应⽤程序,移动电话和客厅设备提供特定的授权流程。该规范及其扩展正在IETF OAuth⼯作组内开发。
OAuth 2.0 的标准是 ⽂件。该⽂件先解释了 OAuth 是什么。OAuth 的核⼼就是向第三⽅应⽤颁发令牌。然后,RFC 6749 接着写道:它定义了获得令牌的四种授权⽅式(authorization grant )。
授权流程图
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
简单⼀点的诉述就是发起⼀个认证请求,根据授权类型去认证服务器认证,如果成功就返回token,再使⽤token去访问资源服务器,token 验证通过就返回被保护的资源。
包含的⾓⾊
OAuth定义了四个⾓⾊:
资源所有者:能够授予对受保护资源的访问权限的实体。当资源所有者是⼀个⼈时,它称为最终⽤户。
资源服务器:托管受保护资源的服务器,能够接受并使⽤访问令牌响应受保护的资源请求。
客户端:对我们的产品来说,QQ、登录是第三⽅登录系统。我们⼜需要第三⽅登录系统的资源(头像、昵称等)
授权服务器:请求授权成功后,服务器向客户端发布访问令牌认证资源所有者并获得授权
授权模式
授权码(authorization-code)
这种⽅式是最常⽤的流程,安全性也最⾼,它适⽤于那些有后端的 Web 应⽤。授权码通过前端传送,令牌则是储存在后端,⽽且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌漏。
第⼀步,A ⽹站提供⼀个链接,⽤户点击后就会跳转到 B ⽹站,授权⽤户数据给 A ⽹站使⽤。下⾯就是 A ⽹站跳转 B ⽹站的⼀个⽰意链接。
服务器IP:服务器PORT/oauth/authorize?
response_type=code& # 固定写法
client_id=CLIENT_ID& # client_id ⾃⼰定义的
redirect_uri=CALLBACK_URL& #回调地址,授权成功跳转到地址并携带code=XXXX,之后再⽤XXXX去申请令牌
scope=read #⾮必须
第⼆步,⽤户跳转后,B ⽹站会要求⽤户登录,然后询问是否同意给予 A ⽹站授权。⽤户表⽰同意,这时 B ⽹站就会跳
回redirect_uri参数指定的⽹址。跳转时,会传回⼀个授权码,就像下⾯这样。
CALLBACK_URL?code=AUTHORIZATION_CODE
第三步,A ⽹站拿到授权码以后,就可以在后端,向 B ⽹站请求令牌。
服务器IP:服务器PORT/oauth/token?
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET&
grant_type=authorization_code&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL
上⾯ URL 中,client_id参数和client_secret参数⽤来让 B 确认 A 的⾝份(client_secret参数是保密的,因此只能在后端发请求),grant_type参数的值是authorization_code,表⽰采⽤的授权⽅式是授权码,code参数是上⼀步拿到的授权
码,redirect_uri参数是令牌颁发后的回调⽹址。
第四步,B ⽹站收到请求以后,就会颁发令牌。
{
"access_token": "0e6d26f3-3ad3-407f-8203-3342f25807ca",
"token_type": "bearer",
"refresh_token": "9941dc19-a167-4173-9895-934f9519363d",
"expires_in": 86399,
"scope": "all",
"username1": "demo",
"license": "wujie"
}
隐藏式(implicit)
有些 Web 应⽤是纯前端应⽤,没有后端。这时就不能⽤上⾯的⽅式了,必须将令牌储存在前端。RFC 6749 就规定了第⼆种⽅式,允许直接向前端颁发令牌。这种⽅式没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)。
第⼀步,A ⽹站提供⼀个链接,要求⽤户跳转到 B ⽹站,授权⽤户数据给 A ⽹站使⽤
服务器IP:服务器PORT/oauth/authorize?
response_type=token& #response_type参数为token,表⽰要求直接返回令牌
client_id=CLIENT_ID&
redirect_uri=CALLBACK_URL&
scope=read
第⼆步,⽤户跳转到 B ⽹站,登录后同意给予 A ⽹站授权。这时,B ⽹站就会跳回redirect_uri参数指定的跳转⽹址,并且把令牌作为 URL 参数,传给 A ⽹站。
服务器IP:服务器PORT/callback#token=ACCESS_TOKEN #token=ACCESS_TOKEN这⾥就是token
注意,令牌的位置是 URL 锚点(fragment),⽽不是查询字符串(querystring),这是因为 OAuth 2.0 允许跳转⽹址是HTTP 协议,因此存在"中间⼈攻击"的风险,⽽浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
这种⽅式安全性很低,所以⼀般⽤于对安全性要求不⾼的场景,并且token有效期很短,⼀般也就是当前session,会话结束就失效。
密码式(password):
如果你⾼度信任某个应⽤,RFC 6749 也允许⽤户把⽤户名和密码,直接告诉该应⽤。该应⽤就使⽤你的密码,申请令牌,这种⽅式称为"密码式"(password)。
第⼀步,A ⽹站要求⽤户提供 B ⽹站的⽤户名和密码。拿到以后,A 就直接向 B 请求令牌。
服务器IP:服务器PORT/oauth/token?
grant_type=password& #password指明使⽤密码模式
username=USERNAME& #⽤户名
password=PASSWORD& #密码
client_id=CLIENT_ID #定义的client
第⼆步,B ⽹站验证⾝份通过后,直接给出令牌。注意,这时不需要跳转,⽽是把令牌放在 JSON 数据⾥⾯,作为 HTTP 回应,A 因此拿到令牌。
{
"access_token": "0e6d26f3-3ad3-407f-8203-3342f25807ca",
"token_type": "bearer",
"refresh_token": "9941dc19-a167-4173-9895-934f9519363d",
"expires_in": 86399,
"scope": "all",
"username1": "demo",
"license": "wujie"
}
这种⽅式毕竟是直接给出了⽤户的账号密码,最好是在⾃⼰的系统内部使⽤的场景。如果不是都必须是⼀种相互⾼度信任的场景客户端凭证(client credentials)
⽤于没有前端的命令⾏应⽤,即在命令⾏下请求令牌。
第⼀步,A 应⽤在命令⾏向 B 发出请求。
服务器IP:服务器PORT/oauth/token?
grant_type=client_credentials& #指定使⽤客户端凭证模式
client_id=CLIENT_ID& #定义的client
client_secret=CLIENT_SECRET #定义的secret
第⼆步,B ⽹站验证通过以后,直接返回令牌。
这种⽅式给出的令牌,是针对第三⽅应⽤的,⽽不是针对⽤户的,即有可能多个⽤户共享同⼀个令牌。
注意,不管哪⼀种授权⽅式,第三⽅应⽤申请令牌之前,都必须先到系统备案,说明⾃⼰的⾝份,然后会拿到两个⾝份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防⽌令牌被滥⽤,没有备案过的第三⽅应⽤,是不会拿到令牌的。
刷新令牌
OAuth 2.0 允许⽤户⾃动更新令牌,当令牌的有效期到了以后,如果让⽤户重新⾛⼀次上⾯的流程,对于⽤户的体验来说相当的不友好。
{
"access_token": "0e6d26f3-3ad3-407f-8203-3342f25807ca",
"token_type": "bearer",
"refresh_token": "9941dc19-a167-4173-9895-934f9519363d",
"expires_in": 86399,
"scope": "all",
"username1": "demo",
"license": "wujie"
}
在我们上⾯请求到的token中,都是同时颁发了access_token以及refresh_token。令牌到期前,⽤户使⽤ refresh token 发⼀个请求,去更新令牌。
服务器IP:服务器PORT/oauth/token?
grant_type=refresh_token& #指定是刷新令牌
client_id=CLIENT_ID& #定义的client
client_secret=CLIENT_SECRET& #定义的secret
refresh_token=REFRESH_TOKEN #使⽤获取令牌时同时返回的refresh_token
B ⽹站验证通过以后,就会颁发新的令牌。
Spring Security
简介
Spring Security是⼀个功能强⼤且⾼度可定制的⾝份验证和访问控制框架。它是⽤于保护基于Spring的应⽤程序的实际标准。
Spring Security是⼀个框架,致⼒于为Java应⽤程序提供⾝份验证和授权。与所有Spring项⽬⼀样,Spring Security的真正强⼤之处在于可以轻松扩展以满⾜⾃定义要求
特点
1. 对⾝份验证和授权的全⾯且可扩展的⽀持
2. 防⽌攻击,例如会话固定,点击劫持,跨站点请求伪造等
3. Servlet API集成
4. 与Spring Web MVC的可选集成
Spring Cloud Security
简介
Spring Cloud Security提供了⼀组原语,⽤于以最少的⿇烦构建安全的应⽤程序和服务。可以在外部(或中央)进⾏⼤量配置的声明式模型通常可以通过中央⾝份管理服务来实现⼤型的,相互协作的远程组件系统。在Cloud Foundry等服务平台中使⽤它也⾮常容易。在Spring Boot和Spring Security OAuth2的基础上,我们可以快速创建实现常见模式(如单点登录,令牌中继和令牌交换)的系统。
适合新手的spring boot特点
1. 在Zuul代理中将SSO令牌从前端中继到后端服务
2. 资源服务器之间的中继令牌
3. 使Feign客户端⾏为类似于OAuth2RestTemplate的(获取令牌等)
4. 在Zuul代理中配置下游⾝份验证
说了这么多东西,其实没有什么⽤处,就是简单的普及⼀下安全相关的技术,⽽且根据最新的相关资料显⽰,Spring官⽅已经不⽀持Spring Security Oauth2了,他们将对这技术进⾏迁移,换句话说就是打算⾃⼰搞⼀个。
有兴趣的可以⾃⼰去了解阅读⼀下。
咱们步⼊正题吧。继续使⽤我们之前搭建好的SpringCloudAlibaba的框架,我们再新建⼀个项⽬。创建授权服务
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.wujie</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>hello-spring-cloud-alibaba-dependencies</artifactId>
</parent>
<groupId>com.wujie</groupId>
<artifactId>hello-spring-cloud-alibaba-nacos-oauth-authorization</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hello-spring-cloud-alibaba-nacos-oauth-authorization</name>
<description>创建授权服务器</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--freemarker,页⾯渲染引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.7.9</version>
</dependency>
<!-- mybatis启动器 -->
<dependency>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论