Spring Security OAuth2建立在Spring Security的基础之上,实现了OAuth2的规范,Spring Cloud Security模块用于构建安全的应用程序和服务。在Spring Boot和Spring Security OAuth2的基础上,我们可以快速创建实现常见模式(如单点登录,令牌中继和令牌交换)的系统。
Spring OAuth2.0 提供者实现原理
Spring OAuth2.0提供者实际上分为:
- 授权服务 Authorization Service
- 资源服务 Resource Service.
1、添加依赖
添加Spring Security 及 Security 的OAuth2 依赖;
spring-cloud-starter-oauth2 是对spring-cloud-starter-security、spring-security-oauth2、spring-security-jwt这3个依赖的整合;
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
2、配置资源服务器
一般情况下,资源服务器指的是,我们提供 API 的应用或服务。例如,订单服务、商品服务。考虑到让整个示例更加简单,本文先将它和授权服务器放在一个 Maven 项目中。
2.1 创建一个 Controller 类
**
* 这是一个示例模块的 Controller ,提供 /api/example/hello 接口。
*/
@RestController
@RequestMapping("/api/example")
public class ExampleController {
@RequestMapping("/hello")
public String hello() {
return "world";
}
}
2.2、 配置资源服务器
// 资源服务配置
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 对 "/api/**" 开启认证
.anyRequest()
.authenticated()
.and()
.requestMatchers()
.antMatchers("/api/**");
}
}
- @Configuration 注解,保证 OAuth2ResourceServer 能够被 SpringBoot 扫描到配置。
- @EnableResourceServer 注解,开启资源服务器。
- 继承( extends ) ResourceServerConfigurerAdapter 类,并覆写 #configure(HttpSecurity http) 方法,配置对 HTTP 请求中,匹配 /api/**" 路径,开启认证的验证。
3、配置授权服务器
在 OAuth2.0 中,定义了四种授权模式:
- 授权码模式( authorization code )
- 密码模式( resource owner password credentials )
- 简化模式( implicit )
- 客户端模式( client credentials )
本文针对authorization code 这种模式进行演示;
3.1 授权码模式
- 配置授权服务器
// 授权服务器配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory() // <1>
// <2> begin ...
.withClient("clientapp").secret("112233") // Client 账号、密码。
.redirectUris("http://localhost:9001/callback") // 配置回调地址,选填。
.authorizedGrantTypes("authorization_code") // 授权码模式
.scopes("read_userinfo", "read_contacts") // 可授权的 Scope
// <2> end ...
// .and().withClient() // 可以继续配置新的 Client // <3>
;
}
}
AuthorizationServerConfigurerAdapter类说明:
- configure(ClientDetailsServiceConfigurer clients) :用来配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息;
- configure(AuthorizationServerEndpointsConfigurer endpoints) :用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services),还有token的存储方式(tokenStore);
- configure(AuthorizationServerSecurityConfigurer security): 用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)。
- 配置登录账号
创建 application.yml文件,并配置如下:
spring:
security:
basic:
enabled: true
user:
name: test
password: 123123
- 启动项目
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 配置请求安全验证
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
}
- 启动项目,获取授权码
浏览器打开:
http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9001/callback&response_type=code&scope=read_userinfo
client_id 参数,必传,为我们在 OAuth2AuthorizationServer 中配置的 Client 的编号。
redirect_url 参数,可选,回调地址。当然,如果 client_id 对应的 Client 未配置 redirectUris 属性,会报错。
response_type 参数,必传,返回结果为授权码。
scope 参数,可选,申请授权的 Scope 。如果多个,使用逗号分隔。
state 参数,可选,表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
未在上述 URL 中体现出来。
浏览器打开后,效果如下:
登录成功,选择允许所有申请的 Scope ,点击【Authorize】按钮,确认授权。如下图:
授权完成,回调 redirect_uri 地址。返回的code:52Ti7n即为授权码,如下图所示:
获取访问令牌:
curl -X POST --user clientapp:112233 http://localhost:8080/oauth/token -H "content-type: application/x-www-form-urlencoded" -d "code=52Ti7n&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9001%2Fcallback&scope=read_userinfo"
- user clientapp:112233 处,填写我们在 OAuth2AuthorizationServer 中配置的 Client 的编号和密码。
- code=UydkmV 处,填写在 获取授权码 中获取的授权码( code ) 。
返回结果示例如下:
{
"access_token": "e60e41f2-2ad0-4c79-97d5-49af38e5c2e8",
"token_type": "bearer",
"expires_in": 43199,
"scope": "read_userinfo"
}
access_token 属性,访问令牌。非空。
token_type 属性,令牌类型,可以是 "bearer" 或 "mac" 类型。非空。
expires_in 属性,过期时间,单位为秒。一般情况下,非空。
scope 属性,权限范围。如果与 Client 申请的范围一致,此项可省略。
refresh_token 属性,刷新令牌,用来获取下一次的访问令牌。
在授权码模式下,允许为空。