关于 SpringSecurity OAuth2 的 4 种模式的简要介绍性文章:
SpringSecurtiy OAuth2 (2) Authorization Code Grant - 授权码模式
SpringSecurtiy OAuth2 (3) Implicit Grant - 隐式授权模式
SpringSecurtiy OAuth2 (4) Resource Owner Password Grant - 密码模式
SpringSecurtiy OAuth2 (5) Client Credentials Grant - 客户端模式
更多细节和底层原理, 稍后会有专门的文章介绍.
适用于应用没有前端, 只有后端. 整个授权过程没有用户介入 (注意, 虽然密码模式也不需要前端, 但是是有用户信息介入的, 客户端授权模式是 4 种模式中唯一一种完全不需要用户介入的模式). 是第三方应用和授权服务器之间, “应用级别” 的行为.
直接与授权服务器交互, 用授权服务器颁发的客户端 ID 和客户端密钥直接去申请访问令牌.
请求 URL 形如:
http://localhost:18709/client-credentials-authorization-server/oauth/token?grant_type=client_credentials&client_id=client-a&client_secret=client-a-p
主要用于第一方应用.
譬如之前在公司中台做了一个对应全公司与外部多方财务系统的财务中间服务, 对内, 就是采取的客户端模式, 将公司内部产品视作客户端, 均要去中间服务申请客户端 ID 和客户端密钥, 然后在用这个凭证信息换取访问令牌以访问中间服务的资源.
├─client-credentials-authorization-server
│ │ pom.xml
│ │ README.md
│ │
│ └─src
│ └─main
│ ├─java
│ │ └─c
│ │ └─c
│ │ └─d
│ │ └─s
│ │ └─s
│ │ └─o
│ │ └─c
│ │ └─c
│ │ └─authorization
│ │ └─server
│ │ │ ClientCredentialsAuthorizationServer.java
│ │ │
│ │ └─configuration
│ │ AuthorizationServerConfiguration.java
│ │ SecurityConfiguration.java
│ │
│ └─resources
│ application.yml
│
└─client-credentials-resource-server
│ pom.xml
│
└─src
└─main
├─java
│ └─c
│ └─c
│ └─d
│ └─s
│ └─s
│ └─o
│ └─c
│ └─c
│ └─resource
│ └─server
│ │ ClientCredentialsResourceServer.java
│ │
│ ├─configuration
│ │ ResourceServerConfiguration.java
│ │
│ └─controller
│ ResourceController.java
│
└─resources
application.yml
由于客户端模式本身就是描述客户端和授权服务器之间的行为的, 所以在客户端模式的授权服务器代码中, 不需要额外指定其他的
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.allowFormAuthenticationForClients().checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// @formatter:off
clients.inMemory()
.withClient("client-a")
.secret(passwordEncoder.encode("client-a-p")).resourceIds("resource-server")
.authorizedGrantTypes("client_credentials")
.scopes("access-resource")
.and()
.withClient("resource-server").secret(passwordEncoder.encode("resource-server-p"))
;
// @formatter:on
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
super.configure(endpoints);
}
// ~ autowired
// -----------------------------------------------------------------------------------------------------------------
@Autowired
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
// ~ bean
// -----------------------------------------------------------------------------------------------------------------
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.formLogin().disable();
http.httpBasic().disable();
http.authorizeRequests().anyRequest().authenticated();
// @formatter:on
}
}
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource-server").tokenServices(remoteTokenServices()).stateless(true);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
private RemoteTokenServices remoteTokenServices() {
final RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
remoteTokenServices.setCheckTokenEndpointUrl("http://localhost:18709/client-credentials-authorization-server/oauth/check_token");
// 客户端授权模式没有用户介入, 是应用程序和应用程序间的交互
remoteTokenServices.setClientId("resource-server");
remoteTokenServices.setClientSecret("resource-server-p");
return remoteTokenServices;
}
}
简单过了一遍最后一种授权模式: 客户端授权.
总的来说授权码模式和隐式模式都需要前端和用户介入, 其中隐式模式甚至可以不需要后端; 密码模式虽然不需要前端支持, 但是仍然需要用户凭证; 而这最后一种客户端模式, 完全不需要用户介入, 是纯粹的客户端与授权服务器之间的行为. 非常适用于内部系统间的认证鉴权.
- To Be Continued -
- 接下来, 我们会详细探讨 Spring Security OAuth2 的更多自定义特性. 包含 ClientDetailsService
, TokenGranter
etc.