spring seciruty oauth2 client配置

Java
212
0
0
2024-03-19
标签   Spring

版本

spring boot 3.2.1 spring seciruty 6.2.1

配置

  • OAuth2 客户端配置文件 application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          auth-client:
            provider: auth-server # 授权服务器(如果不配置,则provider需要使用auth-client作为key)
            client-id: oidc-client # 客户端ID
            client-name: 客户端 # 客户端名称
            client-secret: secret # 客户端密码
            authorization-grant-type: authorization_code # 授权方式
            redirect-uri: http://localhost:8080/login/oauth2/code/auth-server # 授权码模式完成授权后跳转的地址(最后一节为provider.key)
            scope: openid,profile # 请求的scope
        provider:
          auth-server:
            # issuer-uri: http://localhost:8081 自动从授权服务器获取元数据
            authorization-uri: http://localhost:8081/oauth2/authorize # 授权端点
            token-uri: http://localhost:8081/oauth2/token # 令牌获取端点
            user-info-uri: http://localhost:8081/userinfo # 用户信息端点
            jwk-set-uri: http://localhost:8081/oauth2/jwks # JWS端点
            user-name-attribute: sub # 用户名属性(OpenID Connect 默认使用sub声明字段保存用户名,如果自定义用户信息结构则需要改为对应声明字段名)

注: 如果授权服务器开放了元数据端点,可通过配置issuer-uri,自动通过授权服务器获取元数据,无需配置provider中的各端点uri

在这里插入图片描述

源码

  • OAuth2客户端属性映射 org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesMapper
public final class OAuth2ClientPropertiesMapper {
	private static ClientRegistration getClientRegistration(String registrationId,
			OAuth2ClientProperties.Registration properties, Map<String, Provider> providers) {
		// 尝试通过issuer配置获取客户端注册信息(授权服务器元数据)
		Builder builder = getBuilderFromIssuerIfPossible(registrationId, properties.getProvider(), providers);
		if (builder == null) {
			// 如果获取失败则根据配置构造
			builder = getBuilder(registrationId, properties.getProvider(), providers);
		}
		// 使用配置覆盖构造器默认值(没有配置或空值则不应用)
		PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
		map.from(properties::getClientId).to(builder::clientId);
		map.from(properties::getClientSecret).to(builder::clientSecret);
		map.from(properties::getClientAuthenticationMethod)
			.as(ClientAuthenticationMethod::new)
			.to(builder::clientAuthenticationMethod);
		map.from(properties::getAuthorizationGrantType)
			.as(AuthorizationGrantType::new)
			.to(builder::authorizationGrantType);
		map.from(properties::getRedirectUri).to(builder::redirectUri);
		map.from(properties::getScope).as(StringUtils::toStringArray).to(builder::scope);
		map.from(properties::getClientName).to(builder::clientName);
		return builder.build();
	}
	// 尝试通过issuer获取客户端注册信息构造器
	private static Builder getBuilderFromIssuerIfPossible(String registrationId, String configuredProviderId,
			Map<String, Provider> providers) {
		// 如果客户端注册配置中没有配置providerId,则使用客户端注册ID作为providerId
		String providerId = (configuredProviderId != null) ? configuredProviderId : registrationId;
		// provider配置了issuerUri,则通过issuer查询客户端注册信息
		if (providers.containsKey(providerId)) {
			Provider provider = providers.get(providerId);
			String issuer = provider.getIssuerUri();
			if (issuer != null) {
				Builder builder = ClientRegistrations.fromIssuerLocation(issuer).registrationId(registrationId);
				return getBuilder(builder, provider);
			}
		}
		return null;
	}
	// 获取客户端注册信息构造器
	private static Builder getBuilder(String registrationId, String configuredProviderId,
			Map<String, Provider> providers) {
		// 如果客户端注册配置中没有配置providerId,则使用客户端注册ID作为providerId
		String providerId = (configuredProviderId != null) ? configuredProviderId : registrationId;
		// 获取通用provider(GOOGLE,GITHUB,FACEBOOK,OKTA)
		CommonOAuth2Provider provider = getCommonProvider(providerId);
		if (provider == null && !providers.containsKey(providerId)) {
			throw new IllegalStateException(getErrorMessage(configuredProviderId, registrationId));
		}
		// 如果获取到通用provider, 则使用通用provider创建builder,否则使用客户端注册信息创建builder
		Builder builder = (provider != null) ? provider.getBuilder(registrationId)
				: ClientRegistration.withRegistrationId(registrationId);
		// 如果配置信息中包含了provider配置,则将配置信息应用到builder中
		if (providers.containsKey(providerId)) {
			return getBuilder(builder, providers.get(providerId));
		}
		return builder;
	}
}
  • 客户端注册构造器工具类 org.springframework.security.oauth2.client.registration.ClientRegistrations
public final class ClientRegistrations {
	...
	// 从issuer获取客户端注册配置信息
	public static ClientRegistration.Builder fromIssuerLocation(String issuer) {
		Assert.hasText(issuer, "issuer cannot be empty");
		URI uri = URI.create(issuer);
		// 可支持从 OpenID Connect, OAuth授权服务器获取元数据
		return getBuilder(issuer, oidc(uri), oidcRfc8414(uri), oauth(uri));
	}
	...
}