feat:授权模式

This commit is contained in:
xiang
2025-08-30 22:54:49 +08:00
parent 3177fdae38
commit 00a2cf2a0d
3 changed files with 79 additions and 16 deletions

View File

@@ -24,4 +24,11 @@ spring:
user: user:
auth: auth:
issuer: http://127.0.0.1:38011 issuer: http://127.0.0.1:38011
# Web 应用前端回调地址:
# http://localhost:8080/login/oauth2/code/oauth-client-init
# Postman 测试用:
# https://oauth.pstmn.io/v1/callback
# 移动端 APP 自定义 Scheme
# myapp://callback
redirectUrl: http://localhost:8080/login/oauth2/code/oauth-client-init

View File

@@ -0,0 +1,34 @@
spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://rm-bp15t34gqx62jm069ro.mysql.rds.aliyuncs.com:3306/xservice-user?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
username: root
password: xb#UWqnhH24&XpX
driver-class-name: com.mysql.cj.jdbc.Driver
sshConnect: false
redis:
host: r-bp1wt59a6nfyt4e3ltpd.redis.rds.aliyuncs.com
port: 6379
password: Admin@123 # 如果无密码可以省略
database: 0
timeout: 5000
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 1000
user:
auth:
issuer: http://127.0.0.1:38011
# Web 应用前端回调地址:
# http://localhost:8080/login/oauth2/code/oauth-client-init
# Postman 测试用:
# https://oauth.pstmn.io/v1/callback
# 移动端 APP 自定义 Scheme
# myapp://callback
redirectUrl: http://localhost:8080/login/oauth2/code/oauth-client-init

View File

@@ -5,10 +5,12 @@ import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jose.proc.SecurityContext;
import com.xiang.xservice.basic.utils.JwkUtils; import com.xiang.xservice.basic.utils.JwkUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
@@ -21,22 +23,28 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import java.time.Duration;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@RequiredArgsConstructor
public class AuthorizationServerConfig { public class AuthorizationServerConfig {
@Value("${user.auth.issuer}") @Value("${user.auth.issuer}")
private String issuer; private String issuer;
@Value("${user.auth.redirectUrl}")
private String redirectUrl;
private final JdbcTemplate jdbcTemplate;
@Bean @Bean
@Order(1) @Order(1)
@@ -54,7 +62,6 @@ public class AuthorizationServerConfig {
.authorizeRequests(authorizeRequests -> authorizeRequests .authorizeRequests(authorizeRequests -> authorizeRequests
.antMatchers("/public/**").permitAll() .antMatchers("/public/**").permitAll()
.antMatchers("/open/**").permitAll() .antMatchers("/open/**").permitAll()
.antMatchers("/private/**").permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
) )
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
@@ -77,18 +84,33 @@ public class AuthorizationServerConfig {
@Bean @Bean
public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) { public RegisteredClientRepository registeredClientRepository(PasswordEncoder passwordEncoder) {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString()) JdbcRegisteredClientRepository repository = new JdbcRegisteredClientRepository(jdbcTemplate);
.clientId("messaging-client")
.clientSecret(passwordEncoder.encode("secret")) // 演示用,生产请加密 String clientId = "oauth-client-init";
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) RegisteredClient existingClient = repository.findByClientId(clientId);
.authorizationGrantType(AuthorizationGrantType.PASSWORD) if (Objects.isNull(existingClient)) {
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.scope("message.read") .clientId(clientId)
.scope("message.write") .clientSecret(passwordEncoder.encode("xxCompany-xx"))
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build()) .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.build(); .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) // 已过时, 建议自己实现扩展
// todo 暂时内存保存,后续需要配合数据库保存 .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
return new InMemoryRegisteredClientRepository(registeredClient); .redirectUri(redirectUrl)
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder()
.requireAuthorizationConsent(true)
.build())
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofHours(1))
.refreshTokenTimeToLive(Duration.ofDays(30))
.reuseRefreshTokens(true)
.build())
.build();
repository.save(registeredClient);
}
return repository;
} }
@Bean @Bean