文章目录
-
- 引言
- 一、Spring Authorization Server基础
- 二、基础配置与授权服务器设置
- 三、用户认证与客户端管理
- 四、令牌定制与自定义声明
- 五、授权确认页面定制
- 总结
引言
在微服务架构中,统一的身份认证和授权机制至关重要。OAuth2作为行业标准的授权框架,被广泛应用于各类应用系统。Spring Authorization Server项目提供了对OAuth2授权服务器的原生支持,本文将探讨如何使用Spring Security实现一个功能完备的OAuth2授权服务器,包括客户端注册、授权流程配置以及令牌管理,帮助开发者构建安全可靠的认证授权中心。
一、Spring Authorization Server基础
Spring Authorization Server是Spring Security团队开发的框架,用于构建符合OAuth2.1和OpenID Connect 1.0规范的授权服务器。要使用它,首先需要添加相关依赖:
// 在pom.xml中添加以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring–boot–starter–security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring–security–oauth2–authorization–server</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring–boot–starter–web</artifactId>
</dependency>
Spring Authorization Server支持OAuth2.1规范中的多种授权类型,包括授权码模式、客户端凭证模式、刷新令牌模式等,还支持OpenID Connect扩展,可以签发ID令牌用于身份认证。
二、基础配置与授权服务器设置
配置OAuth2授权服务器需要设置安全过滤链和基本参数。以下是核心配置示例:
@Configuration
@EnableWebSecurity
public class AuthorizationServerConfig {
@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(Customizer.withDefaults()); // 启用OpenID Connect
http
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults()));
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/assets/**", "/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client")
.clientSecret(passwordEncoder.encode("secret"))
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/client")
.scope(OidcScopes.OPENID)
.scope("read")
.scope("write")
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(true)
.build())
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(30))
.refreshTokenTimeToLive(Duration.ofDays(1))
.build())
.build();
return new InMemoryRegisteredClientRepository(client);
}
@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);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder()
.issuer("http://auth-server:9000")
.build();
}
// 生成RSA密钥对
private static KeyPair generateRsaKey() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
这个配置类定义了两个安全过滤链(一个用于授权服务器端点,另一个用于常规Web安全),注册了客户端信息,配置了JWT签名密钥,并设置了授权服务器的基本参数。
三、用户认证与客户端管理
授权服务器需要管理用户和客户端信息。以下是用户认证服务的实现:
@Bean
public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build();
UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder.encode("admin"))
.roles("USER", "ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
在实际应用中,通常需要将客户端信息存储在数据库中。可以实现JdbcRegisteredClientRepository或自定义RegisteredClientRepository:
@Component
public class JpaRegisteredClientRepository implements RegisteredClientRepository {
private final ClientRepository clientRepository;
// 实现findById、findByClientId和save方法
// 将RegisteredClient对象与数据库实体进行转换
// …
}
四、令牌定制与自定义声明
OAuth2授权服务器默认使用JWT作为访问令牌格式。可以自定义令牌内容,添加额外的用户信息或业务相关的声明:
@Component
public class CustomJwtTokenCustomizer implements OAuth2TokenCustomizer<JwtEncodingContext> {
@Override
public void customize(JwtEncodingContext context) {
if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
Authentication principal = context.getPrincipal();
JwtClaimsSet.Builder claims = context.getClaims();
claims.claim("user_id", principal.getName());
// 添加用户角色
Set<String> authorities = principal.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());
claims.claim("roles", authorities);
// 添加其他自定义声明
claims.claim("custom_claim", "custom_value");
}
}
}
要启用这个自定义器,需要在配置类中注册它:
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> jwtTokenCustomizer() {
return new CustomJwtTokenCustomizer();
}
五、授权确认页面定制
在授权码流程中,用户需要确认授予客户端的权限范围。可以自定义授权确认页面,提供更好的用户体验:
@Controller
public class AuthorizationConsentController {
private final RegisteredClientRepository clientRepository;
@GetMapping("/oauth2/consent")
public String consentPage(
@RequestParam("client_id") String clientId,
@RequestParam("scope") String scope,
Model model) {
RegisteredClient client = clientRepository.findByClientId(clientId);
model.addAttribute("clientName", client.getClientName());
model.addAttribute("scopes", Arrays.asList(scope.split(" ")));
return "consent";
}
}
在配置中启用自定义确认页面:
authorizationServerConfigurer.authorizationEndpoint(
authorizationEndpoint -> authorizationEndpoint.consentPage("/oauth2/consent")
);
总结
Spring Authorization Server为构建OAuth2授权服务器提供了强大而灵活的支持。通过适当的配置,可以快速实现一个功能完备的认证授权中心,支持多种授权类型和客户端认证方法。本文介绍了Spring Authorization Server的基础配置、客户端注册、用户认证、令牌定制以及授权确认页面的定制方法。在实际应用中,还需要考虑令牌撤销、刷新策略、安全加固等问题,以构建一个安全可靠的OAuth2认证授权体系。合理利用Spring Security的模块化设计和丰富功能,结合业务需求进行定制,可以构建出既满足安全要求又具有良好用户体验的认证授权服务。
评论前必须登录!
注册