前言
Spring Authorization Server 是 Spring 团队最新开发适配 OAuth 协议的授权服务器项目,旨在替代原有的 Spring Security OAuth
经过半年的开发和孵化,目前已经发布了 0.1.0 版本,初步支持授权码、客户端、刷新、注销等 OAuth 协议
本文环境基于 Spring Boot 2.4.2 && authorization-server 0.1.0
Server 搭建
1. maven 依赖
<!--oauth2 server-->
<dependency>
<groupId>org.springframework.security.experimental</groupId>
<artifactId>spring-security-oauth2-authorization-server</artifactId>
<version>0.1.0</version>
</dependency>
<!--security dependency-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 初始化配置
由于官方还未提供对应的 Spring Boot Starter 自动化配置,需要自己配置相关的 @Bean
本配置基于 Spring Boot 2.4.2 请知悉
@Configuration @EnableWebSecurity @Import(OAuth2AuthorizationServerConfiguration.class) public class AuthServerConfiguration {
// 定义 spring security 拦击链规则 @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated() ) .formLogin(withDefaults()); return http.build(); }
// 创建默认登录用户 lengleng / 123456 @Bean public UserDetailsService userDetailsService() { UserDetails userDetails = User.builder() .username("lengleng") .password("{noop}123456") .authorities("ROLE_USER") .build(); return new InMemoryUserDetailsManager(userDetails); } // 创建默认的bean 登录客户端,基于 授权码、 刷新令牌的能力 @Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient client = RegisteredClient.withId("pig") .clientId("pig") .clientSecret("pig") .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) .authorizationGrantTypes(authorizationGrantTypes -> { authorizationGrantTypes.add(AuthorizationGrantType.AUTHORIZATION_CODE); authorizationGrantTypes.add(AuthorizationGrantType.REFRESH_TOKEN); }) .redirectUri("https://pig4cloud.com") .build(); return new InMemoryRegisteredClientRepository(client); } // 指定token 生成的加解密密钥 @Bean @SneakyThrows public JWKSource
jwkSource() { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // @formatter:off RSAKey rsaKey= new RSAKey.Builder(publicKey) .privateKey(privateKey) .keyID(UUID.randomUUID().toString()) .build(); JWKSet jwkSet = new JWKSet(rsaKey); return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); } }
测试
授权码认证
curl --location --request GET 'http://localhost:3000/oauth2/authorize?client_id=pig&client_secret=pig&response_type=code&redirect_uri=https://pig4cloud.com'
获取令牌
curl --location --request POST 'http://localhost:3000/oauth2/token' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code={code}' \
--data-urlencode 'redirect_uri=https://pig4cloud.com'
刷新令牌
curl --location --request POST 'http://localhost:3000/oauth2/token' \
--header 'Authorization: Basic cGlnOnBpZw==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token={refresh_token}' \
撤销令牌
通过 access_token
curl --location --request POST 'http://localhost:3000/oauth2/revoke'
--header 'Authorization: Basic cGlnOnBpZw=='
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'token={access_token}'
--data-urlencode 'token_type_hint=access_token'通过 refresh_token
curl --location --request POST 'http://localhost:3000/oauth2/revoke'
--header 'Authorization: Basic cGlnOnBpZw=='
--header 'Content-Type: application/x-www-form-urlencoded'
--data-urlencode 'token={refresh_token}'
--data-urlencode 'token_type_hint=refresh_token'
内容扩展 | Token 个性化
RegisteredClient 支持个性化 token 设置的入参
RegisteredClient..tokenSettings()
默认配置如下, 包括令牌有效期,刷新令牌控制等
protected static Map<String, Object> defaultSettings() { Map<String, Object> settings = new HashMap<>(); settings.put(ACCESS_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(5)); settings.put(REUSE_REFRESH_TOKENS, true); settings.put(REFRESH_TOKEN_TIME_TO_LIVE, Duration.ofMinutes(60)); return settings; }
总结
由于官方暂时未完善相关的文档,所有的端点入参等需要参考 The OAuth 2.0 Authorization Framework