单点登录是多域名企业站点流行的登录方式。本文以现实生活场景辅助理解,力争彻底理清 OAuth2.0 实现单点登录的原理流程。 同时总结了权限控制的实现方案,及其在微服务架构中的应用。
传统的多点登录系统中,每个站点都实现了本站专用的帐号数据库和登录模块。各站点的登录状态相互不认可,各站点需要逐一手工登录。如下图,有两个术语含义如下:
单点登录,英文是 Single Sign On,缩写为 SSO。
多个站点(192.168.1.20X)共用一台认证授权服务器(192.168.1.110,用户数据库和认证授权模块共用)。用户经由其中任何一个站点(比如 192.168.1.201)登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。
为了直观的理解 OAuth2.0 原理流程,我们假设这样一个生活场景:
(1)档案局A(客户端 / Client):以“档案局ID/密码”标识,是掌握档案资源的机构。并列还有很多档案局B/C/…,每个档案局存储的档案内容(资源 / Resource)不一样,比如政治、经济、军事、文化等;
(2)公民张三(资源所有者 / Resource Owner):以“用户名/密码”标识,需要到各个档案局查档案;
(3)派出所(授权服务器 / Authentication Server):可以是单个巨大的派出所,也可以是数据共享的派出所集群,掌管的信息、提供的对外接口功能有:
张三之前从未到访档案局,第一次来档案局。对照下图序号理解:
张三已经成功访问了档案局A,现在他要访问档案局B。对照下图序号理解:
(1)/(2) 同上;
(3)张三已经有“身份证明信”,直接在“派出所”的“授权信开具处”成功开具“访问档案局B”的授权信;
(4)/(5)/(6) 免了;
(7)“档案局B”的“用户登记处”完成登记;
(8)“档案局B”的“档案处”查得档案。
张三已经成功访问了档案局A,现在他要访问档案局A。对照下图序号理解:
(1)直接成功查到了档案;
(2~8)都免了。
HTTP 协议中,浏览器的 REQUEST 发给服务器之后,服务器如果发现该业务不属于自己管辖,会把你支派到自身服务器或其他服务器(host)的某个接口(uri)。正如我们去政府部门办事,每到一个窗口,工作人员会说“你带上材料A,到本所的X窗口,或者其他Y所的Z窗口”进行下一个手续。
至此,就不难理解 OAuth 2.0 的认证/授权流程,此处不再赘述。请拿下图对照“2.1 生活实例”一节来理解。
根据官方标准,OAuth 2.0 共用四种授权模式:
官方文档:
https://cloud.spring.io/spring-cloud-security/reference/html/
(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
@EnableResourceServer // 启用资源服务器
public class AuthorizationServerApplication {
// ...
}
(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) pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
(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");
}
}
授权服务器中,定义各用户拥有的角色: 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() {
}
}
下图是基本的认证/授权控制方案,主要设计了认证授权服务器上相关数据表的基本定义。可对照本文“2.1 生活实例”一节来理解。
与常规服务架构不同,在微服务架构中,Authorization Server/Resource Server 是作为微服务存在的,用户的登录可以通过API网关一次性完成,无需与无法跳转至内网的 Authorization Server 来完成。