QQ、微信和微博三大社交平台几乎垄断了整个中国的网络通讯,以至于在当今社会,交换社交账号的意义甚至超越了交换名片和个人电话。在这样的背景下,越来越多的应用通过接入这些社交平台的OAuth服务以降低获客成本,同时也可以为用户提供更为便捷的登录体验;政府、企业等组织内部,通常会运行着大量的软件应用、Web服务,选择接入keycloak,Okta等IDaaS服务使得企业在确保信息安全的同时,也能有效降低IT管理成本,实现更为高效的身份和访问管理。
企业在发展壮大的过程中,搭建自有开放平台是从小作坊式管理向规范的平台式进化的体现,具有且不限于以下这些积极意义:
- 为APP端提供统一的接口管控平台。
- 为第三方合作伙伴的业务对接提供授信可控的技术对接平台。
- 搭建基于API的生态体系。
OAuth作为开放平台的代表,在企业级应用开发中占据了举足轻重的地位,每个开发者都应当对它有所了解,不仅是前面章节学习到的OAuth客户端实现,对于授权服务器,我们同样有足够的必要去学习并掌握。
功能概述
授权服务器主要提供OAuth Client注册,用户认证,token分发、验证、刷新等功能,资源服务器则负责处理具体的鉴权逻辑,包括基于scope的鉴权,基于配置的Client的authorities属性的鉴权,以及基于用户角色的的鉴权等多种灵活的方式。
授权服务器和资源服务器可以同时在一个应用内实现,也可以拆分成两个独立的应用。企业中常见的基于授权码模式的架构,一般是由一个授权服务器(本身也是资源服务器)和多个资源服务器组成,如图1所示:
依赖包说明
Spring Security有一个独立的子项目spring-security-oauth,用于提供授权服务器和资源服务器的功能。
Spring Security内嵌的OAuth2模块在Spring Security 5.3版本开始支持授权服务器的功能。
而另一个项目spring-security-oauth2-boot则专门为Spring Boot 2.0上使用spring-security-oauth的场景做了适配,在spring-security-oauth2-boot的帮助下,基于Spring Boot 2.0搭建Oauht2授权服务器将变得非常方便,基本的依赖如下:
<!--oauth2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
编码实现
1. 新建工程
新建一个Spring Boot 2.0工程,命名为auth-server,pom的主要依赖包如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--oauth2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
2. 开启授权服务器功能
与Spring Boot一系列以@Enble为前缀的注解一样,只需要在特定的配置类上加@EnableAuthorizationServer注解就可以了。
@Profile("minimal")
@SpringBootApplication
@EnableAuthorizationServer
public class AuthServerApplicationMinimal {
public static void main(String[] args) {
SpringApplication.run(AuthorizationserverApplicationMinimal.class, args);
}
}
为了方便全方位展示授权服务器的功能,我们需要在一个工程中提供多套配置,Spring Boot的Profile机制可以帮助我们实现不同环境配置的快速切换。
与@EnableWebSecurity类似,@EnableAuthorizationServer注解会自动导入OAuth相关的配置类,并由这些配置类提供绝大多数的默认配置,比如Token的签名方式、有效时间和授权类型等:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AuthorizationServerEndpointsConfiguration.class, AuthorizationServerSecurityConfiguration.class})
public @interface EnableAuthorizationServer {
}
3. 注册OAuth2客户端(Client)
在授权服务器中,至少需要注册一个Client与授权服务器交互。客户端可以直接在配置文件中注册:
- application-minimal.yml
security:
oauth2:
client:
client-id: client
client-secret: client
- application.yml
server:
port: 9999
spring:
profiles:
active: minimal
将被激活的profile设定为minimal。
4. 效果演示
我们配置的客户端默认只支持客户端模式(client credentials),可以在命令行窗口执行以下的命令获取access_token:
curl client:client@localhost:9999/oauth/token -dgrant_type=client_credentials -dscope=any
返回结果:
{
"access_token" : "f05a1ea7-4c80-4583-a123-dc7a99415588",
"token_type" : "bearer",
"expires_in" : 43173,
"scope" : "any"
}
携带access_token便可以访问任何支持OAuth2不透明令牌(Opaque Token),且通过此授权服务器进行授权管理的资源服务器。