OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不 需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。
Spring Security OAuth2.0 授权认证
1. 分布式系统认证方案
1.1 分布式系统概述
具有分布式架构的系统叫分布式系统,将单体结构的系统分为若干服务,服务之间通过网络交互来完成用户的业务处理,当前流行的微服务架构就是分布式系统架构
特点:
- 分布性
- 伸缩性
- 共享性
- 开放性
1.2 分布式认证需求
分布式系统的每个服务都会有认证、授权的需求
需要由独立的认证服务处理系统认证授权的请求
- 统一认证授权
提供独立的认证服务,统一处理认证授权 - 应用接入认证
1.3 分布式认证方案
1.3.1 选型分析
- 基于session的认证方式
- 基于token的认证方式
1.3.2 技术方案
分布式系统认证技术方案:
认证服务(UAA)被封装成一个特殊的微服务
统一认证服务(UAA)承载了OAuth2.0接入方认证、登入用户的认证、授权以及生成令牌的职责,完成实际的用户认证、授权功能
API网关作为系统的唯一入口,为接入方提供定制的API集合
2. OAuth2.0
2.1 OAuth2.0概述
OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不 需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。
OAuth2.0认证流程:
2.2 Spring Cloud Security OAuth2.0
2.2.1 环境介绍
- 授权服务(Authorization Server)
AuthorizationEndpoint 服务于认证请求 默认 URL: /oauth/authorize
TokenEndpoint 服务于访问令牌的请求 默认 URL: /oauth/token - 资源服务(Resource Server)
OAuth2AuthenticationProcessingFilter用来对请求给出的身份令牌解析鉴权
2.2.2 环境搭建
-
父工程
在IDEA中创建Maven工程作为父工程 -
UAA授权服务子工程
工程结构:
- 启动类UAAServer
加入相关注解 - 配置文件application.properties
配置相关信息
- Order资源服务子工程
工程结构:
- 启动类OrderServer
加入相关注解 - 配置文件application.properties
配置相关信息
2.2.3 授权服务器配置
-
EnableAuthorizationServer
可以用 @EnableAuthorizationServer 注解并继承AuthorizationServerConfigurerAdapter来配置OAuth2.0 授权服务器
在Config包下创建AuthorizationServer
主要配置三项内容:
ClientDetailsServiceConfigurer 配置客户端详情服务
AuthorizationServerEndpointsConfigurer 配置令牌的访问端点和令牌服务
AuthorizationServerSecurityConfigurer 配置令牌端点的安全约束 -
配置客户端详细信息
ClientDetailsService负责查找ClientDetails
暂时使用内存方式存储客户端详情信息 -
管理令牌
AuthorizationServerTokenServices 接口定义了一些操作使得我们可以对令牌进行一些必要的管理,令牌可以被用来加载身份信息,里面包含了这个令牌的相关权限
定义TokenConfig,暂时先使用InMemoryTokenStore,生成一个普通的令牌
在AuthorizationServer中定义AuthorizationServerTokenServices -
令牌访问端点配置
AuthorizationServerEndpointsConfigurer 这个对象的实例可以完成令牌服务以及令牌endpoint配置
配置授权类型
配置授权端点的URL -
令牌端点的安全约束
AuthorizationServerSecurityConfigurer 用来配置令牌端点(Token Endpoint)的安全约束 -
web安全配置
在UAA子工程中建立WebSecurityConfig文件
2.2.4 授权码模式
授权码模式交互图:
- 资源拥有者打开客户端,客户端要求资源拥有者给予授权,它将浏览器被重定向到授权服务器,重定向时会附加客户端的身份信息
- 浏览器出现向授权服务器授权页面,之后将用户同意授权
- 授权服务器将授权码(AuthorizationCode)转经浏览器发送给client(通过redirect_uri)
- 客户端拿着授权码向授权服务器索要访问access_token
- 授权服务器返回令牌(access_token)
2.2.5 简化模式
简化模式交互图:
2.2.6 密码模式
密码模式交互图:
2.2.7 客户端模式
2.2.8 资源服务测试
- 资源服务器配置
使用 ResourceServerConfigurer 这个配置对象来进行配置 - 验证token
- 编写资源
- 添加安全访问控制
2.3 JWT令牌
2.3.1 JWT概述
JSON Web Token 用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权
JWT令牌结构:Header头部、Payload负载、Signature签名
2.3.2 配置JWT令牌服务
在UAA中配置JWT令牌服务,即可实现生成JWT格式的令牌
- TokenConfig配置
- 定义JWT令牌服务
2.3.3 生成JWT令牌
2.3.4 校验JWT令牌
将授权服务中的TokenConfig类拷贝到资源服务中
2.4 完善环境配置
生产环境中客户端信息和授权码会存储在数据库中,所以要完善环境的配置
2.4.1 创建表
oauth_client_details 客户端详情表
oauth_code 授权码表
2.4.2 配置授权服务
ClientDetailsService和AuthorizationCodeServices改为从数据库读取数据
3. Spring Security实现分布式系统授权
3.1 需求分析
技术方案:
1、UAA认证服务负责认证授权。
2、所有请求经过 网关到达微服务
3、网关负责鉴权客户端以及请求转发
4、网关将token解析后传给微服务,微服务进行授权。
3.2 注册中心
所有微服务的请求都经过网关,网关从注册中心读取微服务的地址,将请求转发至微服务
注册中心采用Eureka
- 创建Discovery注册中心子工程
- 配置文件 application.yml
- 启动类 DiscoveryServer
3.3 网关
思路:认证服务器生成jwt令牌, 所有请求统一在网关层验证,判断权限等操作
- API网关:
作为OAuth2.0的资源服务器角色,实现接入方权限拦截
进行令牌解析并转发当前登录用户信息(明文token)给微服务 - 微服务:
用户授权拦截(看当前用户是否有权访问该资源)
将用户信息存储进当前线程上下文(有利于后续业务逻辑随时获取当前用户信息)
3.3.1 创建工程
- 创建Gateway网关子工程
- 配置文件 application.properties
在网关上新增路由配置,包括统一认证服务与统一用户服务 - 启动类 GatewayServer
3.3.2 token配置
资源服务器由于需要验证并解析令牌,往往可以通过在授权服务器暴露check_token的Endpoint来完成
配置 TokenConfig
3.3.3 配置资源服务
在ResouceServerConfig中定义资源服务配置,主要配置的内容就是定义一些匹配规则,描述某个接入客户端需要什么样的权限才能访问某个微服务
3.3.4 安全配置
配置 WebSecurityConfig
3.4 转发明文token给微服务
通过Zuul过滤器的方式实现,目的是让下游微服务能够很方便的获取到当前的登录用户信息(明文token)
- 实现Zuul前置过滤器,完成当前登录用户信息提取,并放入转发微服务的request中
- 将fifilter纳入spring 容器
3.5 微服务用户鉴权拦截
对Order资源服务进行改造,增加微服务用户鉴权拦截功能
- 增加测试资源
- Spring Security配置
- 定义filter拦截token,并形成Spring Security的Authentication对象
解析token
新建并填充authentication
将authentication保存进安全上下文
这样,资源服务中就可以方便到的获取用户的身份信息
3.6 集成测试
-
过网关申请令牌
-
校验令牌
-
访问资源服务
3.7 扩展用户信息
方案:扩展username的内容,比如存入json数据内容作为username的内容
- 修改UserDetailService
从数据库查询到user,将整体user转成json存入userDetails对象 - 修改资源服务过滤器
资源服务中的过滤器负责从header中解析json-token,从中即可拿网关放入的用户身份信息