单点登录-OAuth2
单点登录的实现原理
一、共享Session
共享Session可谓是实现单点登录最直接、最简单的方式。将用户认证信息保存于Session中,即以Session内存储的值为用户凭证,这在单个站点内使用是很正常也很容易实现的,而在用户验证、用户信息管理与业务应用分离的场景下即会遇到单点登录的问题,在应用体系简单,子系统很少的情况下,可以考虑采用Session共享的方法来处理这个问题。

二、基于OpenId的单点登录

由上图可以看到,这套单点登录依赖于OpenId的传递,其验证的基础在于OpenId的存储以及发送。
1、当用户第一次登录时,将用户名密码发送给验证服务;
2、验证服务将用户标识OpenId返回到客户端;
3、客户端进行存储;
4、访问子系统时,将OpenId发送到子系统;
5、子系统将OpenId转发到验证服务;
6、验证服务将用户认证信息返回给子系统;
7、子系统构建用户验证信息后将授权后的内容返回给客户端。
这套单点登录验证机制的主要问题在于他基于C/S架构下将用户的OpenId存储于客户端,在子系统之间发送OpenId,而B/S模式下要做到这一点就显得较为困难。为了处理这个问题我们将引出下一种方式,这种方式将解决B/S模式下的OpenId的存储、传递问题。
三、基于Cookie的OpenId存储方案
我们知道,Cookie的作用在于充当一个信息载体在Server端和Browser端进行信息传递,而Cookie一般是以域名为分割的,例如a.xxx.com与b.xxx.com的Cookie是不能互相访问的,但是子域名是可以访问上级域名的Cookie的。即a.xxx.com和b.xxx.com是可以访问xxx.com下的Cookie的,于是就能将顶级域名的Cookie作为OpenId的载体。

1、 在提供验证服务的站点里登录;
2、 将OpenId写入顶级域名Cookie里;
3、 访问子系统(Cookie里带有OpenId)
4、 子系统取出OpenId通过并向验证服务发送OpenId
5、 返回用户认证信息
6、 返回授权后的内容
四、B/S多域名环境下的单点登录处理

五、安全问题
单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。
1 什么是单点登录
1.1 多点登录
传统的多点登录系统中,每个站点都实现了本站专用的帐号数据库和登录模块。各站点的登录状态相互不认可,各站点需要逐一手工登录。如下图,有两个术语含义如下:
认证(authentication): 验证用户的身份;
授权(authorization): 验证用户的访问权限。

1.2 单点登录
单点登录,英文是 Single Sign On,缩写为 SSO。多个站点(192.168.1.20X)共用一台认证授权服务器(192.168.1.110,用户数据库和认证授权模块共用)。用户经由其中任何一个站点(比如 192.168.1.201)登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。

2 OAuth2 认证授权的原理流程
2.1 生活实例【★★重点★★】
为了直观的理解 OAuth2.0 原理流程,我们假设这样一个生活场景:
(1)档案局A(客户端 / Client):以“档案局ID/密码”标识,是掌握档案资源的机构。并列还有很多档案局B/C/…,每个档案局存储的档案内容(资源 / Resource)不一样,比如政治、经济、军事、文化等;
(2)公民张三(资源所有者 / Resource Owner):以“用户名/密码”标识,需要到各个档案局查档案;
(3)派出所(授权服务器 / Authentication Server):可以是单个巨大的派出所,也可以是数据共享的派出所集群,掌管的信息、提供的对外接口功能有:
档案局信息:所有档案局的“档案局ID/密码”,证明档案局的身份;
公民信息:所有公民的“用户名/密码”,能提供张三是张三的用户身份证明(
认证 / Authentication)公民对于档案局的权限:有张公民和档案局的权限的映射表,可查得各公民对各档案局是否有操作权限(
授权 / Authorization)。通常,设计中会增加官职(角色 / Role)一层,各公民属于哪个官职(角色),哪个官职(角色)对于特定档案局有操作权限。
2.1.1 张三首次访问档案局A
张三之前从未到访档案局,第一次来档案局。对照下图序号理解:
(1)张三来到“档案局A”的“档案处”,该处要求实名登记后才能查询,被指示到“用户登记处”办理(HTTP重定向);
(2)张三来到“档案局A”的“用户登记处”,既不能证明身份(认证),又不能证明自己有查档案A的权限(授权)。张三携带档案局A的标识(client-id),被重定向至“授权信开具处”;
(3)张三来到“派出所”的“授权信开具处”,出示档案局A的标识,希望开具授权信(授权)。该处要求首先证明身份(认证),被重定向至“用户身份验证处”;
(4)张三来到“派出所”的“用户身份验证处”,领取了用户身份表(网页登录表单 Form);
(5)张三填上自己的用户名和密码,交给(提交 / Submit)“用户身份验证处”,该处从私用数据库中查得用户名密码匹配,确定此人是张三,开具身份证明信,完成 认证。张三带上身份证明信和档案局A的标识,被重定向至“授权信开具处”;
(6)张三再次来到“授权信开具处”,出示身份证明信和档案局A的标识,该处从私用数据库中查得,张三的官职是市长级别(角色),该官职具有档案局A的查询权限,就开具“允许张三查询档案局A”的授权信(授权码 / code),张三带上授权信被重定向至“档案局”的“用户登录处”;
(7)张三到了“档案局”的“用户登录处”,该处私下拿出档案局A的标识(client-id)和密码,再附上张三出示的授权信(code),向“派出所”的“腰牌发放处”为张三申请的“腰牌”(token),将来张三可以带着这个腰牌表明身份和权限。又被重定向到“档案处”;
(8)张三的会话(Session)已经关联上了腰牌(token),可以直接通过“档案处”查档案。

2.1.2 张三首次访问档案局B
张三已经成功访问了档案局A,现在他要访问档案局B。对照下图序号理解:
(1)/(2) 同上;
(3)张三已经有“身份证明信”,直接在“派出所”的“授权信开具处”成功开具“访问档案局B”的授权信;
(4)/(5)/(6) 免了;
(7)“档案局B”的“用户登记处”完成登记;
(8)“档案局B”的“档案处”查得档案。

2.1.3 张三再次访问档案局A
张三已经成功访问了档案局A,现在他要访问档案局A。对照下图序号理解:
(1)直接成功查到了档案;
(2~8)都免了。

2.2 HTTP 重定向原理
HTTP 协议中,浏览器的 REQUEST 发给服务器之后,服务器如果发现该业务不属于自己管辖,会把你支派到自身服务器或其他服务器(host)的某个接口(uri)。正如我们去政府部门办事,每到一个窗口,工作人员会说“你带上材料A,到本所的X窗口,或者其他Y所的Z窗口”进行下一个手续。
2.3 SSO 工作流程
至此,就不难理解 OAuth 2.0 的认证/授权流程,此处不再赘述。请拿下图对照“2.1 生活实例”一节来理解。

2.4 OAuth2.0 进阶
根据官方标准,OAuth 2.0 共用四种授权模式:
Authorization Code: 用在服务端应用之间,这种最复杂,也是本文采用的模式;Implicit: 用在移动app或者web app(这些app是在用户的设备上的,如在手机上调起微信来进行认证授权)Resource Owner Password Credentials(password): 应用直接都是受信任的(都是由一家公司开发的,本例子使用)Client Credentials: 用在应用API访问。

3 基于 SpringBoot 实现认证/授权
3.1 授权服务器(Authorization Server)
(1) pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
(2) application.properties
server.port=8110 ## 监听端口
(3) AuthorizationServerApplication.java
(4) 配置授权服务的参数
@EnableResourceServer // 启用资源服务器
public class AuthorizationServerApplication {
// ...
}
@Configuration
@EnableAuthorizationServer
public class Oauth2AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("webapp").secret("secret") //客户端 id/secret
.authorizedGrantTypes("authorization code") //授权妈模式
.scopes("user_info")
.autoApprove(true) //自动审批
.accessTokenValiditySeconds(3600); //有效期1hour
}
} @Configuration
public class Oauth2WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize/oauth/logout")
.and().authorizeRequests().anyRequest().authenticated()
.and().formLogin().permitAll();
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin123").roles("ADMIN");
}
}
3.2 客户端(Client, 业务网站)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
(1) pom.xml
(2) application.properties
server port=8080
security.oauth2.client.client-id=webapp
security.oauth2.client.client-secret=secret
security.oauth2.client.access-token-uri=http://localhost:8110/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:8110/oauth/authorize
security.oauth2.resource.user-info-uri=http://localhost:8110/oauth/user
(3) 配置 WEB 安全
@Configuration
@EnableOAuth2Sso
public class Oauth2WebsecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**").authorizeRequests()
.antMatchers("/", "/login").permitAll()
.anyRequest().authenticated();
}
} @RestController
public class Oauth2ClientController {
@GetMapping("/")
public ModelAndView index() {
return new ModelAndView("index");
} @GetMapping("/welcome")
public ModelAndView welcome() {
return new ModelAndView("welcome");
}
}
3.3 用户权限控制(基于角色)
授权服务器中,定义各用户拥有的角色: user=USER, admin=ADMIN/USER, root=ROOT/ADMIN/USER
业务网站中(client),注解标明哪些角色可
@RestController
public class Oauth2ClientController {
@GetMapping("/welcome")
public ModelAndView welcome() {
return new ModelAndView("welcome");
} @GetMapping("/api/user")
@PreAuthorize("hasAuthority('USER')")
public Map<String, Object> apiUser() {
} @GetMapping("/api/admin")
@PreAuthorize("hasAuthority('ADMIN')")
public Map<String, Object> apiAdmin() {
} @GetMapping("/api/root")
@PreAuthorize("hasAuthority('ROOT')")
public Map<String, Object> apiRoot() {
}
}
4 综合运用
4.1 权限控制方案
下图是基本的认证/授权控制方案,主要设计了认证授权服务器上相关数据表的基本定义。可对照本文“2.1 生活实例”一节来理解。

4.2 在微服务架构中的应用
与常规服务架构不同,在微服务架构中,Authorization Server/Resource Server 是作为微服务存在的,用户的登录可以通过API网关一次性完成,无需与无法跳转至内网的 Authorization Server 来完成。

单点登录-OAuth2的更多相关文章
- OAuth2实现单点登录SSO
1. 前言 技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,“一看就会,一做就错”.网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那么回事儿,简直让人抓 ...
- CAS的单点登录和oauth2的最大区别
CAS的单点登录时保障客户端的用户资源的安全 oauth2则是保障服务端的用户资源的安全 CAS客户端要获取的最终信息是,这个用户到底有没有权限访问我(CAS客户端)的资源. oauth2获取的最终信 ...
- Spring Security Oauth2 单点登录案例实现和执行流程剖析
Spring Security Oauth2 OAuth是一个关于授权的开放网络标准,在全世界得到的广泛的应用,目前是2.0的版本.OAuth2在“客户端”与“服务提供商”之间,设置了一个授权层(au ...
- IdentityServer4之SSO(基于OAuth2.0、OIDC)单点登录、登出
IdentityServer4之SSO(基于OAuth2.0.OIDC)单点登录.登出 准备 五个Web站点: 1.localhost:5000 : 认证服务器.2 ...
- Spring Security OAuth2 SSO 单点登录
基于 Spring Security OAuth2 SSO 单点登录系统 SSO简介 单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自 ...
- Spring Security OAuth2实现单点登录
1.概述 在本教程中,我们将讨论如何使用 Spring Security OAuth 和 Spring Boot 实现 SSO(单点登录). 本示例将使用到三个独立应用 一个授权服务器(中央认证机制) ...
- OAuth2.0 原理流程及其单点登录和权限控制
2018年07月26日 07:21:58 kefeng-wang 阅读数:5468更多 所属专栏: Java微服务构架 版权声明:[自由转载-非商用-非衍生-保持署名]-转载请标明作者和出处. h ...
- (十一) 整合spring cloud云架构 - SSO单点登录之OAuth2.0登录流程(2)
上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...
- oauth2.0实现sso单点登录的方式和相关代码
SSO介绍 什么是SSO 百科:SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他 ...
- OAuth2.0认证和授权以及单点登录
https://www.cnblogs.com/shizhiyi/p/7754721.html OAuth2.0认证和授权机制讲解 2017-10-30 15:33 by shizhiyi, 2273 ...
随机推荐
- PicGo+CloudFire搭建免费图床
目录 CloudFire对象存储 创建bucket 配置域名 配置 Bucket 访问 API PicGO配置 参考博客 CloudFire对象存储 | CloudFire提供对象存储服务,每个月有1 ...
- shell脚本安装卸载统一脚本
#!/bin/bash set -e OUT_DIR=out function usage() { cat - <<-EOF SlightShift-SPB Kit Usage: $0 & ...
- 基于Java+SpringBoot心理测评心理测试系统功能实现七
一.前言介绍: 1.1 项目摘要 心理测评和心理测试系统在当代社会中扮演着越来越重要的角色.随着心理健康问题日益受到重视,心理测评和心理测试系统作为评估个体心理状态.诊断心理问题.制定心理治疗方案的工 ...
- 基于.NET开源、功能强大且灵活的工作流引擎框架
前言 工作流引擎框架在需要自动化处理复杂业务流程.提高工作效率和确保流程顺畅执行的场景中得到了广泛应用.今天大姚给大家推荐一款基于.NET开源.功能强大且灵活的工作流引擎框架:elsa-core. 框 ...
- 7.Kubernetes集群YAML文件详解
Kubernetes集群YAML文件详解 概述 k8s 集群中对资源管理和资源对象编排部署都可以通过声明样式(YAML)文件来解决,也就是可以把需要对资源对象操作编辑到YAML 格式文件中,我们把这种 ...
- 快速量产低功耗 4G 定位方案?Air201 模组来搞定!
今天我们来了解的是Air201模组快速量产低功耗 4G 定位方案,希望大家有所收获. 寻寻觅觅低功耗4G定位方案? 一个Air201就够了! --定位准.体积小.功耗低,助力行业客户快速量产! 01 ...
- 4、oracle进程讲解
进程结构 server process服务器进程 前台进程(foreground process):server process(服务器进程) 用户连接到数据库实例以后,暂时可以认为是:对每一个用户连 ...
- 【Azure Function】FTP上传了Python Function文件后,无法在门户页面加载函数的问题
问题描述 通过FTP的方式,把本地能正常运行的Python Function文件上传到云上后,无法加载函数列表问题. 1:上传 function_app.py,requirements.txt文件到 ...
- java公式解析器学习与开发(2)——前缀表达式
释义 前缀表达式就是前序表达式. 前缀表达式就是不含括号的算术表达式,而且它是将运算符写在前面,操作数写在后面的表达式,为纪念其发明者波兰数学家Jan Lukasiewicz也称为"波兰式& ...
- 记一次 .NET某hdp智能柜系统 卡死分析
一:背景 1. 讲故事 停了一个月时间没有更新博客了,主要是这段时间有些许事情导致心神不宁,我这个人也比较浮躁所以无法潜心修炼,事情如下: 被狗咬了 也不知道是不是出门没看黄历,在小区门口店里买烟,被 ...