OAuth2.0 原理流程及其单点登录和权限控制
单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程。同时总结了权限控制的实现方案,及其在微服务架构中的应用。
作者:王克锋
出处:https://kefeng.wang/2018/04/06/oauth2-sso/
版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。
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 进阶
- RFC 6749: The OAuth 2.0 Authorization Framework
- RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage
- 帮你深入理解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>
- 1
- 2
- 3
- 4
(2) application.properties
server.port=8110 ## 监听端口
- 1
(3) AuthorizationServerApplication.java
@EnableResourceServer // 启用资源服务器
public class AuthorizationServerApplication {
// ...
}
- 1
- 2
- 3
- 4
(4) 配置授权服务的参数
@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");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
3.2 客户端(Client, 业务网站)
(1) pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
- 1
- 2
- 3
- 4
(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
- 1
- 2
- 3
- 4
- 5
- 6
(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");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
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() {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
4 综合运用
4.1 权限控制方案
下图是基本的认证/授权控制方案,主要设计了认证授权服务器上相关数据表的基本定义。可对照本文“2.1 生活实例”一节来理解。
4.2 在微服务架构中的应用
与常规服务架构不同,在微服务架构中,Authorization Server/Resource Server 是作为微服务存在的,用户的登录可以通过API网关一次性完成,无需与无法跳转至内网的 Authorization Server 来完成。
OAuth2.0 原理流程及其单点登录和权限控制的更多相关文章
- IdentityServer4之SSO(基于OAuth2.0、OIDC)单点登录、登出
IdentityServer4之SSO(基于OAuth2.0.OIDC)单点登录.登出 准备 五个Web站点: 1.localhost:5000 : 认证服务器.2 ...
- 七、spring boot 1.5.4 集成shiro+cas,实现单点登录和权限控制
1.安装cas-server-3.5.2 官网:https://github.com/apereo/cas/releases/tag/v3.5.2 下载地址:cas-server-3.5.2-rele ...
- OAuth2.0认证流程是如何实现的?
导读 大家也许都有过这样的体验,我们登录一些不是特别常用的软件或网站的时候可以使用QQ.微信或者微博等账号进行授权登陆.例如我们登陆豆瓣网的时候,如果不想单独注册豆瓣网账号的话,就可以选择用微博或者微 ...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-3.微信Oauth2.0交互流程讲解
笔记 3.微信Oauth2.0交互流程讲解 简介:讲解微信Oauth2.0交互流程 参考:https://open.weixin.qq.com/cgi-bin/sho ...
- springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期
写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...
- 手工搭建基于ABP的框架(3) - 登录,权限控制与日志
为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7695258.html 本篇将实现登录.权限控制.日志配置与审计日志的功能.首先我 ...
- Token认证登录以及权限控制
IdentityServer4实现Token认证登录以及权限控制 相关知识点 不再对IdentityServer4做相关介绍,博客园上已经有人出了相关的系列文章,不了解的可以看一下: 蟋蟀大神的: ...
- C#搭建Oauth2.0认证流程以及代码示例
我认为对于一个普遍问题,必有对应的一个简洁优美的解决方案.当然这也许只是我的一厢情愿,因为根据宇宙法则,所有事物总归趋于混沌,而OAuth协议就是混沌中的产物,不管是1...0a还是2.,单看版本号就 ...
- OAuth2.0原理与实现
弄懂了原理流程,才可以搭建出来.更重要的是,可以根据原理流程自定义搭建,甚至可以完全自己实现一套,最后运行效果和原理和这个对得上就成功了,不要总期待标准答案! 首先参考两篇博客: 阮一峰的博客以及张开 ...
随机推荐
- Restful对于URL的简化
REST是英文representational state transfer(表象性状态转变)或者表述性状态转移,它是web服务的一种架构风格.使用HTTP,URI,XML,JSON,HTML等广泛流 ...
- js中的prototype原型解析
在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...
- King Arthur's Birthday Celebration
每天抛一个硬币,硬币正面朝上的几率是p,直到抛出k次正面为止结束,第一天抛硬币需花费1,第二天花费3,然后是5,7,9……以此类推,让我们求出抛硬币的天数的期望和花费的期望. 天数期望: A.投出了k ...
- SET操作符
一:MySQL交集INTERSECT运算符 1.介绍 INTERSECT运算符是一个集合运算符,它只返回两个查询或更多查询的交集. 语法: INTERSECT运算符比较两个查询的结果,并返回由左和右查 ...
- oj提交时常见错误归纳
Presentation Error: 常见的PE错误应该有以下的几种情况: 每行输出之后有空行 每两行输出之间有空行 一行中,每个输出数字(或字符串,等)之间有空格 一行中,每个输出数字(或字符串, ...
- javascript模拟flash头像裁切上传
是的,jq已经有类似的插件了,或者干脆用flash算了,为什么我还要自己写?因为造(wo)轮(bu)子(hui)也(flash)是一个学习的过程,轮子不会造,将来怎么造飞机?先来一张最终效果图: 一. ...
- 【python学习-3】python数据类型
1.数字 在python 2.x中,数字类型有4种,int.long.float 和 complex(复数):而python 3 中,只有 int.float 和 complex 3种,python ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-1
Preface 博主刚放假回家就进了医院,今天刚完事儿,来续写第二本书 Ready 我们来总结一下上一本书的笔记中我们的一些规定 1. 数学表达式 我们采用小写粗黑体代表向量,大写粗黑体代表矩阵, ...
- java 注解 总结
http://www.importnew.com/23564.html 注解的好处: 1.能够读懂别人写的代码,特别是框架相关的代码. 2.本来可能需要很多配置文件,需要很多逻辑才能实现的内容,就可以 ...
- android touch事件分发流程
韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha 三个方法:分发触摸事件dispatchTouchEvent.在触摸事件的时候onTouc ...