Spring Security OAuth2
Spring Security OAuth2
标签(空格分隔): Spring
1. oAuth(Open Authorization)
OAuth协议为用户资源的授权(增删改查)提供了一个安全, 开放而又简易的标准. 和以往授权方式不同之处是oAuth的授权不会使第三方触及到用户的账号信息. 即第三方无需使用用户的用户名和密码就可以申请获得该用户的资源授权. 因此oAuth本身第安全是无害的.
2. Spring Security
Spring Security是一个安全框架, 可以为Spring的企业级应用系统提供声明式的安全访问控制. Spring Security基于Servlet过滤器, IOC和AOP, 为Web请求和方法调用提供身份认证和授权处理, 避免了代码耦合, 减少了大量的重复工作.
3. 应用场景
对于一个系统来说, 他可能提供了不同的服务在不同的设备上, 此时我们需要在不同的设备上去访问这些服务. 那么用户如何去获取自己的那部分资源呢? 可以想到的做法就是提供自己的账号和密码, 登录成功之后就可以获取了. 但是其存在以下问题.
- 对于相关性不高的服务, 我们可能对其采取分别部署, 那么我们访问不同服务的时候都需要登录么?
- 如果第三方程序想要接入我们的服务, 难道我们需要提供账号和密码给第三方应用程序, 让他记录后再访问我们的资源么?
- 如何限定 第三方 服务的访问权限?
- 如果有用户修改了密码收回了权限, 那么第三方的应用程序会全部失效.
- 密码知道的人越多, 泄露的可能就越大.
oAuth在"客户端"与"服务提供商"之间, 设置了一个授权层. 客户端无法直接登录访问服务提供商, 只能登录授权层, 以此将用户和客户端区分开来, 客户端登录授权层 所有的令牌(token), 和用户密码不同. 用户在登录的时候, 指定授权层令牌的权限范围和有效期. 客户端登录授权层以后, 服务商根据令牌的授权范围和有效期, 向客户端提供用户的存储资料.
其实上面说的和我们在做微服务的时候用的SSO, 差不多. 在网关把服务聚合完毕之后, 通过网关试图去访问服务, 但是在没有授权令牌(token)的时候, 服务提供者会将我们的请求踢到SSO模块. 在哪里进行授权获取token之后, 才可以访问SSO. 其SSO就是服务和客户端(浏览器)之间的授权层.
SSO流程. 用户访问服务, 发现没有token, 服务将请求重定向到SSO. 输入账号密码之后, 生成token作为Cookie传给浏览器. token作为键, 用户信息作为值存储到Redis缓存中. 再次访问服务提供者, 服务提供者根据Cookie中的token, 查询Redis, 得到用户信息, 授权访问. 有比较大的相似之处.
4. 开放平台
这个一般是类似于你做了一个QQ这样的产品, 其他的服务提供商想要让QQ的庞大用户群去使用他们的服务的时候, 一般会使用你做的开放平台, 让其他的服务提供商通过你的认证服务器
5. 令牌的刷新和访问
Access Token是客户端访问资源服务器的令牌, 拥有这个令牌代表着得到了用户的授权. 然而这个授权应该是临时的, 有一定有效期的(SSO中利用Redis的过期机制实现). 这个可以降低因为token泄露带来的风险. 引入有效期之后token过期, 用户就需要重新登录, 如果有效期过短, 那么用户体验就很差, 为了兼顾安全和用户体验, oAuth2引入了Refresh Token机制.
5.1 Refresh Token
Refresh Token的作用是用来刷新Access Token的, 认证服务器提供一个刷新接口, 例如:
www.x-power.press/refresh?refresh_token=&client_id=
传入 Refresh Token和Client Id之后, 认证服务器通过验证后会返回一个全新的Access Token. 为了安全oAuth2做了一下两点:
- oAuth2要求, refresh token一定是保存在客户端的服务器上, 而不能存放在客户端上, 调用接口的时候, 也是服务器到服务器的访问(资源服务器到认证服务器)
- oAuth2引入了
client_secret
机制. 即每一个client_id
都对应一个client_secret
. 这个client_secret
会在客户端申请client_id
的时候,随着client_secret
一起分配给客户端(分配 不是放入). 客户端必须要client_secret
妥善的保存在服务器上, 绝对不能泄露, 刷新Access Token的时候需要验证client_secret
.
实际上的刷新接口类似于:
http://www.x-power.press/refresh?refresh_token=&client_id=&client_secret=
.
以上就是refresh token的运行原理, refresh token的有效期非常长, 会在用户授权的时候, 随着Access token一定重定向到回调URL传递给客户端.
实际流程如下:
- 第三方应用请求授权(我们的应用)
- 用户同意授权(输入账号密码), 并返回一个授权码.
- 第三方应用根据授权码,向授权服务器认证授权.
- 授权服务器校验授权码, 校验通过返回第三方应用令牌Access token
- 第三方应用根据令牌, 向资源服务器请求相关资源
- 资源服务器验证令牌, 校验通过, 并返回给第三方所请求的资源.
6. 授权模式
客户端必须得到用户的授权, 才能获得令牌. oAuth2定义了四种授权方式.
- implicit code: 简化模式, 太监被二次阉割之后的版本.
- authorization code: 授权码模式.
- resource owner password credentials: 密码模式
- client credentials :客户端模式
6.1 简化模式
简化模式用于纯静态页面应用. 所谓的纯静态页面应用, 也就是应用没有在服务器上执行代码的权限, 只有JS代码的控制权. (通过GitHub制作自己的博客, 就是纯静态应用. 但是其可以存储数据, 所以我认为在这里下面的声明不成立, 是可以做到Refresh token刷新的.)
该场景之下, 应用是没有持久化存储的能力的. 因此, 按照oAuth2的规定, 这种应用是拿不到 Refresh Token的. 其整个授权流程如下:
6.2 授权码模式
授权码模式适用于有自己服务器的应用, 它是一个一次性的临时凭证, 用来换区access_token
和refresh_token
. 认证服务器提供了一个类似这样的接口:
https://www.x-power.com/exchange?code=&client_id=&client_secret=
其需要传入code
, client_id
以及client_secret
. 验证通过之后, 返回access_token
和, 一旦换取成功
code`立即作废. 不能再使用第二次.
这个 code 的作用是保护 token 的安全性。上一节说到,简单模式下,token 是不安全的。这是因为在第 4 步当中直接把 token 返回给应用。而这一步容易被拦截、窃听。引入了 code 之后,即使攻击者能够窃取到 code,但是由于他无法获得应用保存在服务器的 client_secret,因此也无法通过 code 换取 token。而第 5 步,为什么不容易被拦截、窃听呢?这是因为,首先,这是一个从服务器到服务器的访问,黑客比较难捕捉到;其次,这个请求通常要求是 https 的实现。即使能窃听到数据包也无法解析出内容。
有了这个 code,token 的安全性大大提高。因此,oAuth2.0 鼓励使用这种方式进行授权,而简单模式则是在不得已情况下才会使用
6.3 密码模式
密码模式中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向 "服务商提供商" 索要授权。在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分。
一个典型的例子是同一个企业内部的不同产品要使用本企业的 oAuth2.0 体系。在有些情况下,产品希望能够定制化授权页面。由于是同个企业,不需要向用户展示“xxx将获取以下权限”等字样并询问用户的授权意向,而只需进行用户的身份认证即可。这个时候,由具体的产品团队开发定制化的授权界面,接收用户输入账号密码,并直接传递给鉴权服务器进行授权即可。
有一点需要特别注意的是,在第 2 步中,认证服务器需要对客户端的身份进行验证,确保是受信任的客户端。
6.4 客户端模式
如果信任关系再进一步,或者调用者是一个后端的模块,没有用户界面的时候,可以使用客户端模式。鉴权服务器直接对客户端进行身份验证,验证通过后,返回 token。
7. RBAC(Role-Based Access Control)
用户通过角色身份和不同的权限相关联. 简单地说就是, 一个用户有若干个角色,每一个角色有若干权限. 这样就构成了用户-角色-权限
的授权模型. 在这种模型之中, 用户和角色之间, 角色和权限之间. 一般就是一对多的关系.
在oAuth2中我们需要对静态资源和动态资源的访问都做出控制.
- 静态资源: 数据列(用户表中密码不想让你访问, 你只可以访问用户名,图像.) 纵向资源
- 动态资源: 文章, 相册. 横向资源
对于每一类资源的CRUD. 都拥有这四个中的哪几个权限?
Python的Django 自带的后台 就用的是oAuth2, 在自带后台里面就可以设置对于每一类资源的访问权限, 控制权限.