我想动态更改客户端注册的范围。 我知道如何以这种方式设置注册:
spring:
security:
oauth2:
client:
registration:
custom:
client-id: clientId
client-secret: clientSecret
authorization-grant-type: client_credentials
provider:
custom:
token-uri: http://localhost:8081/oauth/token
如何以编程方式配置此功能?
您需要提供自定义
ClientRegistrationRepository
bean。它在docs中进行了描述。
@Configuration
public class OAuth2LoginConfig {
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
(如果它很愚蠢但有效,那么它并不愚蠢)
所有相关部分将始终使用
ClientRegistrationRepository
来查找 ClientRegistration(以及范围)。
所以我解决这个问题的黑客方法是围绕
InMemoryClientRegistrationRepository
构建一个包装器。就我而言,我希望允许客户端请求任何其他范围,因此我想从查询参数添加其他范围scope
。
这是此解决方案的示例代码:
@Bean
public ClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) {
final List<ClientRegistration> registrations = new ArrayList<>(OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values());
// this is the ClientRegistrationRepository that would be used by default configuration
final ClientRegistrationRepository parent = new InMemoryClientRegistrationRepository(registrations);
// this lambda is our wrapper around the configuration based ClientRegistrationRepository
return (registrationId) -> {
final ClientRegistration clientRegistration = parent.findByRegistrationId(registrationId);
if (clientRegistration == null) {
return null;
}
final HttpServletRequest request = Optional.ofNullable(RequestContextHolder.getRequestAttributes())
.filter(ServletRequestAttributes.class::isInstance)
.map(ServletRequestAttributes.class::cast)
.map(ServletRequestAttributes::getRequest)
.orElse(null);
final String query;
if (request == null || (query = request.getQueryString()) == null) {
return clientRegistration;
}
final List<String> scopeQueryParam = parseQuery(query).get(OAuth2ParameterNames.SCOPE);
if (scopeQueryParam == null) {
return clientRegistration;
}
final Set<String> scopes = scopeQueryParam.stream()
.flatMap((v) -> Arrays.stream(v.split(" ")))
.collect(Collectors.toSet());
if (clientRegistration.getScopes().containsAll(scopes)) {
return clientRegistration;
}
final Set<String> resultingScopes = new HashSet<>(scopes);
resultingScopes.addAll(clientRegistration.getScopes());
return ClientRegistration.withClientRegistration(clientRegistration)
.scope(resultingScopes)
.build();
};
}
private static MultiValueMap<String, String> parseQuery(String query) {
final MultiValueMap<String, String> result = new LinkedMultiValueMap<>();
final String[] pairs = query.split("&");
String[] pair;
for (String _pair : pairs) {
pair = _pair.split("=");
if (pair.length >= 1) {
final List<String> values = result.computeIfAbsent(URLDecoder.decode(pair[0], StandardCharsets.UTF_8), (k) -> new ArrayList<>());
if (pair.length >= 2) {
values.add(URLDecoder.decode(pair[1], StandardCharsets.UTF_8));
}
}
}
return result;
}
我已在 Azure 门户上注册了我的应用程序。我需要知道客户名称和注册 ID 之间的区别。 @matejko219 你能帮助我找到我的应用程序的registrationId吗?