1. 概述
在引入Java 社区两年半之后,VMWare发布了Spring Authorization Server 1.0。Spring 授权服务器项目构建在Spring Security之上,支持创建OpenID Connect 1.0身份提供者和OAuth 2.1授权服务器。该项目取代了不再维护的 Spring Security OAuth项目。
Spring Authorization Server 也是基于Spring Framework 6.0并且需要 Java 17 作为最低版本。该项目支持功能列表中所述的授权授予、令牌格式、客户端身份验证和协议端点。
2. 演示程序
示例应用程序用于演示了使用Spring Initializr创建的 Spring Boot 应用程序的基本配置。示例应用程序是基于 REST 的,并且需要spring-boot-starter-web依赖项pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
为了演示登录功能,请考虑创建 REST 端点的示例:
@RestController
public class TimeController {
@GetMapping("/time")
public String retrieveTime() {
DateTimeFormatter dateTimeFormatter =
DateTimeFormatter.ofPattern("HH:mm:ss");
LocalTime localTime = LocalTime.now();
return dateTimeFormatter.format(localTime);
}
}
一个基本的 Spring Boot 应用程序类用于通过先前创建的 REST 端点启动应用程序:
@SpringBootApplication
public class TimeApplication {
public static void main(String[] args) {
SpringApplication.run(TimeApplication.class, args);
}
}
启动应用程序并打开 url http://localhost:8080/time 后,显示时间:
21:00:34
现在添加了 Spring Authorization Server 依赖项:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>1.0.0</version>
</dependency>
再次启动应用程序时,将记录密码,例如:
Using generated security password: d73d5904-25a1-44ed-91e1-a32c4c5aedb8
现在当浏览到http://localhost:8080/time 时,请求被重定向到 http://localhost:8080/login 并显示以下页面:
默认用户名user和登录密码可用于登录,之后请求将重定向到http://localhost:8080/time?continue并再次显示时间。
Developing Your First Application文档详细介绍了 @Bean
Spring Authorization Server 所需的几个组件,这些组件应在带有注释的类中定义 @Configuration
。第一个 bean 用于定义 OAuth2协议端点:
@Bean
@Order(1)
public SecurityFilterChain protocolFilterChain(HttpSecurity http)
throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http
.exceptionHandling((exceptions) -> exceptions
.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults());
return http.build();
}
第二个 bean 用于定义 Spring Security Authentication:
@Bean
@Order(2)
public SecurityFilterChain authenticationFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
存储用户的正确解决方案应该用于实际产品,但是这个简化的示例将用户james和密码gosling存储在内存中:
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("james")
.password("gosling")
.roles("FOUNDER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
新客户在内存中注册RegisteredClientRepository
:
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient =
RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("id")
.clientSecret("secret")
.clientAuthenticationMethod(
ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri(
"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("message.read")
.scope("message.write")
.clientSettings(
ClientSettings.builder()
.requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
访问令牌在以下 bean 的帮助下使用**com.nimbusds.jose.jwk.RSAKey
and not进行签名java.security.interfaces.RSAKey
**:
@Bean
public JWKSource<SecurityContext> jwkSource() {
KeyPair keyPair = generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
private static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
JwtDecoder
用来解码签名的access tokens ,这里使用的是com.nimbusds.jose.proc.SecurityContext
而不是org.springframework.security.core.context.SecurityContext
:
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
最后,AuthorizationServerSettings
用于配置 OAuth2 授权服务器:
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
现在浏览 http://localhost:8080/time 时 ,可以使用密码为gosling的用户james来查看当前时间。 执行这些步骤后,可以扩展应用程序以使用各种 OAuth2 和 OpenID Connect 1.0 功能。
3.更多
其他参考资料可以查看入门指南。
原文地址