Spring Authorization Server 如何构建高效授权中心?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1417个文字,预计阅读时间需要6分钟。
Spring Authorization Server 实现授权中心,源码地址:[链接]Spring Security 提供对 OAuth 2.0 框架的全面支持。Spring Authorization Server 的优势在于替代 Spring Security OAuth,支持 OAuth 2.1 授权框架。
Spring Authorization Server 实现授权中心源码地址
当前,Spring Security 对 OAuth 2.0 框架提供了全面的支持。Spring Authorization Server 出现的含义在于替换 Spring Security OAuth,交付 OAuth 2.1 授权框架。 Spring 官方已弃用 Spring Security OAuth。
本文涉及的组件版本如下:
spring-security-oauth2-authorization-server 项目由 Spring Security 团队领导,**社区驱动**。
本文的目的:
- 搭建授权中心示例
- fork 当前项目从而免去一些工作
本 demo 的结构
- root
- [[#auth-center|授权中心]]
- [[#user-service|用户服务]]
- [[#client-gateway|移动端网关]]
OAuth 2.1 支持三种许可类型,[[OAuth 2.1 授权框架#授权码许可]]、[[OAuth 2.1 授权框架#客户端证书许可]]、[[OAuth 2.1 授权框架#刷新令牌许可]]。
auth-center build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:0.2.3'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// runtimeOnly 'mysql:mysql-connector-java'
runtimeOnly "com.h2database:h2"
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
config
...
@EnableWebSecurity
@Slf4j
public class DefaultSecurityConfig {
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity 127.0.0.1:9100/login/oauth2/code/mobile-gateway-client-oidc")
.redirectUri("127.0.0.1:9100/authorized")
.scope(OidcScopes.OPENID)
.scope("message.read")
.scope("message.write")
.build();
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder().issuer("localhost:9000").build();
}
@Bean
public EmbeddedDatabase embeddedDatabase() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
.build();
}
- 这里的两个 config 中有两个 SecurityFilterChain 类。调用顺序是 authorizationServerSecurityFilterChain、defaultSecurityFilterChain。
- registeredClientRepository 用于注册 client。这里的两个 redirectUri 中地址来自于[[#mobile-gateway|移动端网关]]。
server:
port: 9000
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
org.springframework.security.oauth2: INFO
启动服务
在浏览器中输入:localhost:9000/.well-known/openid-configuration,得到以下内容。
// 20220510135753
// localhost:9000/.well-known/openid-configuration
{
"issuer": "localhost:9000",
"authorization_endpoint": "localhost:9000/oauth2/authorize",
"token_endpoint": "localhost:9000/oauth2/token",
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
"client_secret_jwt",
"private_key_jwt"
],
"jwks_uri": "localhost:9000/oauth2/jwks",
"userinfo_endpoint": "localhost:9000/userinfo",
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid"
]
}
user-service
用户服务在 demo 中的角色是资源服务器。
build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
config
...
@EnableWebSecurity
public class ResourceServerConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity localhost:9000
启动服务
资源服务器目前不需要做额外配置,只需要启动即可。
client-gateway build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "org.springframework:spring-webflux"
implementation "io.projectreactor.netty:reactor-netty"
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
这里引入 org.springframework:spring-webflux 、io.projectreactor.netty:reactor-netty 的原因在于使用了 WebClient。
...
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoopbackIpRedirectFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServerName().equals("localhost") && request.getHeader("host") != null) {
UriComponents uri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
.host("127.0.0.1").build();
response.sendRedirect(uri.toUriString());
return;
}
filterChain.doFilter(request, response);
}
}
该配置用于转换地址。将 localhost 转换为 127.0.0.1。
...
@EnableWebSecurity
@Slf4j
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity 127.0.0.1:9100/login/oauth2/code/{registrationId}"
scope: openid
client-gateway-authorization-code:
provider: spring
client-id: mobile-gateway-client
client-secret: 123456
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: "127.0.0.1:9100/authorized"
scope: message.read,message.write
provider:
spring:
issuer-uri: localhost:9000
user-service:
base-uri: 127.0.0.1:9001/menu/list
启动服务
在浏览器中输入:127.0.0.1:9100
输入账号密码:user1/password,这里的用户在 [[#auth-center#config]] 中配置。得到以下内容:
总结- spring-authorization-server 目前还没有正式发布。文档较少。
- 还有一些需要完善的点。比如用户持久化、client 持久化。
- 此 demo 还要继续更新,为了能和本文对应,所以对应的 git tag 为
primitive-man。
本文共计1417个文字,预计阅读时间需要6分钟。
Spring Authorization Server 实现授权中心,源码地址:[链接]Spring Security 提供对 OAuth 2.0 框架的全面支持。Spring Authorization Server 的优势在于替代 Spring Security OAuth,支持 OAuth 2.1 授权框架。
Spring Authorization Server 实现授权中心源码地址
当前,Spring Security 对 OAuth 2.0 框架提供了全面的支持。Spring Authorization Server 出现的含义在于替换 Spring Security OAuth,交付 OAuth 2.1 授权框架。 Spring 官方已弃用 Spring Security OAuth。
本文涉及的组件版本如下:
spring-security-oauth2-authorization-server 项目由 Spring Security 团队领导,**社区驱动**。
本文的目的:
- 搭建授权中心示例
- fork 当前项目从而免去一些工作
本 demo 的结构
- root
- [[#auth-center|授权中心]]
- [[#user-service|用户服务]]
- [[#client-gateway|移动端网关]]
OAuth 2.1 支持三种许可类型,[[OAuth 2.1 授权框架#授权码许可]]、[[OAuth 2.1 授权框架#客户端证书许可]]、[[OAuth 2.1 授权框架#刷新令牌许可]]。
auth-center build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:0.2.3'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
// runtimeOnly 'mysql:mysql-connector-java'
runtimeOnly "com.h2database:h2"
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
config
...
@EnableWebSecurity
@Slf4j
public class DefaultSecurityConfig {
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity 127.0.0.1:9100/login/oauth2/code/mobile-gateway-client-oidc")
.redirectUri("127.0.0.1:9100/authorized")
.scope(OidcScopes.OPENID)
.scope("message.read")
.scope("message.write")
.build();
JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository(jdbcTemplate);
registeredClientRepository.save(registeredClient);
return registeredClientRepository;
}
@Bean
public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) {
return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository);
}
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
public ProviderSettings providerSettings() {
return ProviderSettings.builder().issuer("localhost:9000").build();
}
@Bean
public EmbeddedDatabase embeddedDatabase() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/oauth2-authorization-consent-schema.sql")
.addScript("org/springframework/security/oauth2/server/authorization/client/oauth2-registered-client-schema.sql")
.build();
}
- 这里的两个 config 中有两个 SecurityFilterChain 类。调用顺序是 authorizationServerSecurityFilterChain、defaultSecurityFilterChain。
- registeredClientRepository 用于注册 client。这里的两个 redirectUri 中地址来自于[[#mobile-gateway|移动端网关]]。
server:
port: 9000
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
org.springframework.security.oauth2: INFO
启动服务
在浏览器中输入:localhost:9000/.well-known/openid-configuration,得到以下内容。
// 20220510135753
// localhost:9000/.well-known/openid-configuration
{
"issuer": "localhost:9000",
"authorization_endpoint": "localhost:9000/oauth2/authorize",
"token_endpoint": "localhost:9000/oauth2/token",
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
"client_secret_jwt",
"private_key_jwt"
],
"jwks_uri": "localhost:9000/oauth2/jwks",
"userinfo_endpoint": "localhost:9000/userinfo",
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"client_credentials",
"refresh_token"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"scopes_supported": [
"openid"
]
}
user-service
用户服务在 demo 中的角色是资源服务器。
build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
config
...
@EnableWebSecurity
public class ResourceServerConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity localhost:9000
启动服务
资源服务器目前不需要做额外配置,只需要启动即可。
client-gateway build.gradleplugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.insight.into.life'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation "org.springframework:spring-webflux"
implementation "io.projectreactor.netty:reactor-netty"
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.2'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
这里引入 org.springframework:spring-webflux 、io.projectreactor.netty:reactor-netty 的原因在于使用了 WebClient。
...
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoopbackIpRedirectFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServerName().equals("localhost") && request.getHeader("host") != null) {
UriComponents uri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
.host("127.0.0.1").build();
response.sendRedirect(uri.toUriString());
return;
}
filterChain.doFilter(request, response);
}
}
该配置用于转换地址。将 localhost 转换为 127.0.0.1。
...
@EnableWebSecurity
@Slf4j
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity 127.0.0.1:9100/login/oauth2/code/{registrationId}"
scope: openid
client-gateway-authorization-code:
provider: spring
client-id: mobile-gateway-client
client-secret: 123456
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: "127.0.0.1:9100/authorized"
scope: message.read,message.write
provider:
spring:
issuer-uri: localhost:9000
user-service:
base-uri: 127.0.0.1:9001/menu/list
启动服务
在浏览器中输入:127.0.0.1:9100
输入账号密码:user1/password,这里的用户在 [[#auth-center#config]] 中配置。得到以下内容:
总结- spring-authorization-server 目前还没有正式发布。文档较少。
- 还有一些需要完善的点。比如用户持久化、client 持久化。
- 此 demo 还要继续更新,为了能和本文对应,所以对应的 git tag 为
primitive-man。

