SpringCloud微服务实战——搭建企业级开发框架(四十一):集成JustAuth实现通用第三方登录功能【一】

举报
全栈程序猿 发表于 2023/07/21 11:10:03 2023/07/21
【摘要】   前面我们详细介绍了SSO、OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端。目前很多平台都提供了单点登录授权服务器功能,比如我们经常用到的QQ登录、微信登录、新浪微博登录、支付宝登录等等。  如果我们自己的系统需要调用第三方登录,那么我们就需要实现单点登录客户端,然后跟需要对接的平台调试登录...

  前面我们详细介绍了SSO、OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端。目前很多平台都提供了单点登录授权服务器功能,比如我们经常用到的QQ登录、微信登录、新浪微博登录、支付宝登录等等。
  如果我们自己的系统需要调用第三方登录,那么我们就需要实现单点登录客户端,然后跟需要对接的平台调试登录SDK。JustAuth是第三方授权登录的工具类库,对接了国外内数十家第三方登录的SDK,我们在需要实现第三方登录时,只需要集成JustAuth工具包,然后配置即可实现第三方登录,省去了需要对接不同SDK的麻烦。
  JustAuth官方提供了多种入门指南,集成使用非常方便。但是如果要贴合我们自有开发框架的业务需求,还是需要进行整合优化。下面根据我们的系统需求,从两方面进行整合:一是支持多租户功能,二是和自有系统的用户进行匹配。

一、JustAuth多租户系统配置

  • GitEgg多租户功能实现介绍

  GitEgg框架支持多租户功能,从多租户的实现来讲,目前大多数平台都是在登录界面输入租户的标识来确定属于哪个租户,这种方式简单有效,但是对于用户来讲体验不是很好。我们更希望的多租户功能是能够让用户无感知,且每个租户有自己不同的界面展示。
  GitEgg在实现多租户功能时,考虑到同一域名可以设置多个子域名,每个子域名可对应不同的租户。所以,对于多租户的识别方式,首先是根据浏览器当前访问的域名或IP地址和系统配置的多租户域名或IP地址信息进行自动识别,如果是域名或IP地址存在多个,或者未找到相关配置时,才会由用户自己选择属于哪个租户。

  • 自定义JustAuth配置文件信息到数据库和缓存

  在JustAuth的官方Demo中,SpringBoot集成JustAuth是将第三方授权信息配置在yml配置文件中的,对于单租户系统来说,可以这样配置。但是,对于多租户系统,我们需要考虑多种情况:一种是整个多租户系统使用同一套第三方授权,授权之后再由用户选择绑定到具体的租户;另外一种是每个租户配置自己的第三方授权,更具差异化。
  出于功能完整性的考虑,我们两种情况都实现,当租户不配置自有的第三方登录参数时,使用的是系统默认自带的第三方登录参数。当租户配置了自有的第三方登录参数时,就是使用租户自己的第三方授权服务器。我们将JustAuth原本配置在yml配置文件中的第三方授权服务器信息配置在数据库中,并增加多租户标识,这样在不同租户调用第三方登录时就是相互隔离的。

1. JustAuth配置信息表字段设计

  首先我们通过JustAuth官方Demo justauth-spring-boot-starter-demo 了解到JustAuth主要的配置参数为:

  • JustAuth功能启用开关
  • 自定义第三方登录的配置信息
  • 内置默认第三方登录的配置信息
  • Http请求代理的配置信息
  • 缓存的配置信息
justauth:
  # JustAuth功能启用开关
  enabled: true
  # 自定义第三方登录的配置信息
  extend:
    enum-class: com.xkcoding.justauthspringbootstarterdemo.extend.ExtendSource
    config:
      TEST:
        request-class: com.xkcoding.justauthspringbootstarterdemo.extend.ExtendTestRequest
        client-id: xxxxxx
        client-secret: xxxxxxxx
        redirect-uri: http://oauth.xkcoding.com/demo/oauth/test/callback
      MYGITLAB:
        request-class: com.xkcoding.justauthspringbootstarterdemo.extend.ExtendMyGitlabRequest
        client-id: xxxxxx
        client-secret: xxxxxxxx
        redirect-uri: http://localhost:8443/oauth/mygitlab/callback
  # 内置默认第三方登录的配置信息
  type:
    GOOGLE:
      client-id: xxxxxx
      client-secret: xxxxxxxx
      redirect-uri: http://localhost:8443/oauth/google/callback
      ignore-check-state: false
      scopes:
        - profile
        - email
        - openid
  # Http请求代理的配置信息
  http-config:
    timeout: 30000
    proxy:
      GOOGLE:
        type: HTTP
        hostname: 127.0.0.1
        port: 10080
      MYGITLAB:
        type: HTTP
        hostname: 127.0.0.1
        port: 10080
  # 缓存的配置信息
  cache:
    type: default
    prefix: 'demo::'
    timeout: 1h

  在对配置文件存储格式进行设计时,结合对多租户系统的需求分析,我们需要选择哪些配置是系统公共配置,哪些是租户自己的配置。比如自定义第三方登录的enum-class这个是需要由系统开发的,是整个多租户系统的功能,这种可以看做是通用配置,但是在这里,考虑到后续JustAuth系统升级,我们不打算破坏原先配置文件的结构,所以我们仍选择各租户隔离配置。
  我们将JustAuth配置信息拆分为两张表存储,一张是配置JustAuth开关、自定义第三方登录配置类、缓存配置、Http超时配置等信息的表(t_just_auth_config),这些配置信息的同一特点是与第三方登录系统无关,不因第三方登录系统的改变而改变;还有一张表是配置第三方登录相关的参数、Http代理请求表(t_just_auth_source)。租户和t_just_auth_config为一对一关系,和t_just_auth_source为一对多关系。

t_just_auth_config(租户第三方登录功能配置表)表定义:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_just_auth_config
-- ----------------------------
DROP TABLE IF EXISTS `t_just_auth_config`;
CREATE TABLE `t_just_auth_config`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',
  `enabled` tinyint(1) NULL DEFAULT NULL COMMENT 'JustAuth开关',
  `enum_class` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自定义扩展第三方登录的配置类',
  `http_timeout` bigint(20) NULL DEFAULT NULL COMMENT 'Http请求的超时时间',
  `cache_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缓存类型',
  `cache_prefix` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缓存前缀',
  `cache_timeout` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '缓存超时时间',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户第三方登录功能配置表' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

t_just_auth_source(租户第三方登录信息配置表)表定义:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_just_auth_source
-- ----------------------------
DROP TABLE IF EXISTS `t_just_auth_source`;
CREATE TABLE `t_just_auth_source`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户id',
  `source_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '第三方登录的名称',
  `source_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '第三方登录类型:默认default  自定义custom',
  `request_class` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自定义第三方登录的请求Class',
  `client_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户端id:对应各平台的appKey',
  `client_secret` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '客户端Secret:对应各平台的appSecret',
  `redirect_uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录成功后的回调地址',
  `alipay_public_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支付宝公钥:当选择支付宝登录时,该值可用',
  `union_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否需要申请unionid,目前只针对qq登录',
  `stack_overflow_key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Stack Overflow Key',
  `agent_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '企业微信,授权方的网页应用ID',
  `user_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '企业微信第三方授权用户类型,member|admin',
  `domain_prefix` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '域名前缀 使用 Coding 登录和 Okta 登录时,需要传该值。',
  `ignore_check_state` tinyint(1) NOT NULL DEFAULT 0 COMMENT '忽略校验code state}参数,默认不开启。',
  `scopes` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '支持自定义授权平台的 scope 内容',
  `device_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '设备ID, 设备唯一标识ID',
  `client_os_type` int(11) NULL DEFAULT NULL COMMENT '喜马拉雅:客户端操作系统类型,1-iOS系统,2-Android系统,3-Web',
  `pack_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '喜马拉雅:客户端包名',
  `pkce` tinyint(1) NULL DEFAULT NULL COMMENT ' 是否开启 PKCE 模式,该配置仅用于支持 PKCE 模式的平台,针对无服务应用,不推荐使用隐式授权,推荐使用 PKCE 模式',
  `auth_server_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Okta 授权服务器的 ID, 默认为 default。',
  `ignore_check_redirect_uri` tinyint(1) NOT NULL DEFAULT 0 COMMENT '忽略校验 {@code redirectUri} 参数,默认不开启。',
  `proxy_type` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Http代理类型',
  `proxy_host_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'Http代理Host',
  `proxy_port` int(11) NULL DEFAULT NULL COMMENT 'Http代理Port',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `creator` bigint(20) NULL DEFAULT NULL COMMENT '创建者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `operator` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
  `del_flag` tinyint(2) NULL DEFAULT 0 COMMENT '是否删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '租户第三方登录信息配置表' ROW_FORMAT = DYNAMIC;
SET FOREIGN_KEY_CHECKS = 1;
2. 使用GitEgg代码生成工具生成JustAuth配置信息的CRUD代码

  我们将JustAuth配置信息管理的相关代码和JustAuth实现业务逻辑的代码分开,配置信息我们在系统启动时加载到Redis缓存,JustAuth在调用时,直接调用Redis缓存中的配置。
  前面讲过如何通过数据库表设计生成CRUD的前后端代码,这里不再赘述,生成好的后台代码我们放在gitegg-service-extension工程下,和短信、文件存储等的配置放到同一工程下,作为框架的扩展功能。

基础配置:

image.png

第三方列表:

image.png

3. 代码生成之后,需要做初始化缓存处理,即在第三方配置服务启动的时候,将多租户的配置信息初始化到Redis缓存中。
  • 初始化的CommandLineRunner类 InitExtensionCacheRunner.java
/**
 * 容器启动完成加载资源权限数据到缓存
 * @author GitEgg
 */
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Component
public class InitExtensionCacheRunner implements CommandLineRunner {
    
    private final IJustAuthConfigService justAuthConfigService;
    
    private final IJustAuthSourceService justAuthSourceService;

    @Override
    public void run(String... args) {

        log.info("InitExtensionCacheRunner running");
    
    
        // 初始化第三方登录主配置
        justAuthConfigService.initJustAuthConfigList();

        // 初始化第三方登录 第三方配置
        justAuthSourceService.initJustAuthSourceList();


    }
}
  • 第三方登录主配置初始化方法
    /**
     * 初始化配置表列表
     * @return
     */
    @Override
    public void initJustAuthConfigList() {
        QueryJustAuthConfigDTO queryJustAuthConfigDTO = new QueryJustAuthConfigDTO();
        queryJustAuthConfigDTO.setStatus(GitEggConstant.ENABLE);
        List<JustAuthConfigDTO> justAuthSourceInfoList = justAuthConfigMapper.initJustAuthConfigList(queryJustAuthConfigDTO);
        
        // 判断是否开启了租户模式,如果开启了,那么角色权限需要按租户进行分类存储
        if (enable) {
            Map<Long, List<JustAuthConfigDTO>> authSourceListMap =
                    justAuthSourceInfoList.stream().collect(Collectors.groupingBy(JustAuthConfigDTO::getTenantId));
            authSourceListMap.forEach((key, value) -> {
                String redisKey = AuthConstant.SOCIAL_TENANT_CONFIG_KEY + key;
                redisTemplate.delete(redisKey);
                addJustAuthConfig(redisKey, value);
            });
            
        } else {
            redisTemplate.delete(AuthConstant.SOCIAL_CONFIG_KEY);
            addJustAuthConfig(AuthConstant.SOCIAL_CONFIG_KEY, justAuthSourceInfoList);
        }
    }
    
    private void addJustAuthConfig(String key, List<JustAuthConfigDTO> configList) {
        Map<String, String> authConfigMap = new TreeMap<>();
        Optional.ofNullable(configList).orElse(new ArrayList<>()).forEach(config -> {
            try {
                authConfigMap.put(config.getTenantId().toString(), JsonUtils.objToJson(config));
                redisTemplate.opsForHash().putAll(key, authConfigMap);
            } catch (Exception e) {
                log.error("初始化第三方登录失败:{}" , e);
            }
        });

    }
  • 第三方登录参数配置初始化方法
    /**
     * 初始化配置表列表
     * @return
     */
    @Override
    public void initJustAuthSourceList() {
        QueryJustAuthSourceDTO queryJustAuthSourceDTO = new QueryJustAuthSourceDTO();
        queryJustAuthSourceDTO.setStatus(GitEggConstant.ENABLE);
        List<JustAuthSourceDTO> justAuthSourceInfoList = justAuthSourceMapper.initJustAuthSourceList(queryJustAuthSourceDTO);
        
        // 判断是否开启了租户模式,如果开启了,那么角色权限需要按租户进行分类存储
        if (enable) {
            Map<Long, List<JustAuthSourceDTO>> authSourceListMap =
                    justAuthSourceInfoList.stream().collect(Collectors.groupingBy(JustAuthSourceDTO::getTenantId));
            authSourceListMap.forEach((key, value) -> {
                String redisKey = AuthConstant.SOCIAL_TENANT_SOURCE_KEY + key;
                redisTemplate.delete(redisKey);
                addJustAuthSource(redisKey, value);
            });
            
        } else {
            redisTemplate.delete(AuthConstant.SOCIAL_SOURCE_KEY);
            addJustAuthSource(AuthConstant.SOCIAL_SOURCE_KEY, justAuthSourceInfoList);
        }
    }
    
    private void addJustAuthSource(String key, List<JustAuthSourceDTO> sourceList) {
        Map<String, String> authConfigMap = new TreeMap<>();
        Optional.ofNullable(sourceList).orElse(new ArrayList<>()).forEach(source -> {
            try {
                authConfigMap.put(source.getSourceName(), JsonUtils.objToJson(source));
                redisTemplate.opsForHash().putAll(key, authConfigMap);
            } catch (Exception e) {
                log.error("初始化第三方登录失败:{}" , e);
            }
        });
    }
4. 引入JustAuth相关依赖jar包
  • 在gitegg-platform-bom工程中引入JustAuth包和版本,JustAuth提供了SpringBoot集成版本justAuth-spring-security-starter,如果简单使用,可以直接引用SpringBoot集成版本,我们这里因为需要做相应的定制修改,所以引入JustAuth基础工具包。
······
        <!-- JustAuth第三方登录 -->
        <just.auth.version>1.16.5</just.auth.version>
        <!-- JustAuth SpringBoot集成 -->
        <just.auth.spring.version>1.4.0</just.auth.spring.version>
······
            <!--JustAuth第三方登录-->
            <dependency>
                <groupId>me.zhyd.oauth</groupId>
                <artifactId>JustAuth</artifactId>
                <version>${just.auth.version}</version>
            </dependency>
            <!--JustAuth SpringBoot集成-->
            <dependency>
                <groupId>com.xkcoding.justauth</groupId>
                <artifactId>justauth-spring-boot-starter</artifactId>
                <version>${just.auth.spring.version}</version>
            </dependency>
······

  • 新建gitegg-platform-justauth工程,用于实现公共自定义代码,并在pom.xml中引入需要的jar包。
    <dependencies>
        <!-- gitegg Spring Boot自定义及扩展 -->
        <dependency>
            <groupId>com.gitegg.platform</groupId>
            <artifactId>gitegg-platform-boot</artifactId>
        </dependency>
        <!--JustAuth第三方登录-->
        <dependency>
            <groupId>me.zhyd.oauth</groupId>
            <artifactId>JustAuth</artifactId>
        </dependency>
        <!--JustAuth SpringBoot集成-->
        <dependency>
            <groupId>com.xkcoding.justauth</groupId>
            <artifactId>justauth-spring-boot-starter</artifactId>
            <!-- 不使用JustAuth默认版本-->
            <exclusions>
                <exclusion>
                    <groupId>me.zhyd.oauth</groupId>
                    <artifactId>JustAuth</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-data-redis</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-autoconfigure</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-configuration-processor</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
3. 自定义实现获取和实例化多租户第三方登录配置的AuthRequest工厂类GitEggAuthRequestFactory.java
/**
 * GitEggAuthRequestFactory工厂类
 *
 * @author GitEgg
 */
@Slf4j
@RequiredArgsConstructor
public class GitEggAuthRequestFactory {
    
    private final RedisTemplate redisTemplate;
    
    private final AuthRequestFactory authRequestFactory;
    
    private final JustAuthProperties justAuthProperties;
    
    /**
     * 是否开启租户模式
     */
    @Value("${tenant.enable}")
    private Boolean enable;

    public GitEggAuthRequestFactory(AuthRequestFactory authRequestFactory, RedisTemplate redisTemplate, JustAuthProperties justAuthProperties) {
        this.authRequestFactory = authRequestFactory;
        this.redisTemplate = redisTemplate;
        this.justAuthProperties = justAuthProperties;
    }

    /**
     * 返回当前Oauth列表
     *
     * @return Oauth列表
     */
    public List<String> oauthList() {
        // 合并
        return authRequestFactory.oauthList();
    }

    /**
     * 返回AuthRequest对象
     *
     * @param source {@link AuthSource}
     * @return {@link AuthRequest}
     */
    public AuthRequest get(String source) {
        
        if (StrUtil.isBlank(source)) {
            throw new AuthException(AuthResponseStatus.NO_AUTH_SOURCE);
        }
    
        // 组装多租户的缓存配置key
        String authConfigKey = AuthConstant.SOCIAL_TENANT_CONFIG_KEY;
        if (enable) {
            authConfigKey += GitEggAuthUtils.getTenantId();
        } else {
            authConfigKey = AuthConstant.SOCIAL_CONFIG_KEY;
        }
    
        // 获取主配置,每个租户只有一个主配置
        String sourceConfigStr = (String) redisTemplate.opsForHash().get(authConfigKey, GitEggAuthUtils.getTenantId());
        AuthConfig authConfig = null;
        JustAuthSource justAuthSource = null;
        AuthRequest tenantIdAuthRequest = null;
        if (!StringUtils.isEmpty(sourceConfigStr))
        {
            try {
                // 转为系统配置对象
                JustAuthConfig justAuthConfig = JsonUtils.jsonToPojo(sourceConfigStr, JustAuthConfig.class);
                // 判断该配置是否开启了第三方登录
                if (justAuthConfig.getEnabled())
                {
                    // 根据配置生成StateCache
                    CacheProperties cacheProperties = new CacheProperties();
                    if (!StringUtils.isEmpty(justAuthConfig.getCacheType())
                            && !StringUtils.isEmpty(justAuthConfig.getCachePrefix())
                            && null != justAuthConfig.getCacheTimeout())
                    {
                        cacheProperties.setType(CacheProperties.CacheType.valueOf(justAuthConfig.getCacheType().toUpperCase()));
                        cacheProperties.setPrefix(justAuthConfig.getCachePrefix());
                        cacheProperties.setTimeout(Duration.ofMinutes(justAuthConfig.getCacheTimeout()));
                    }
                    else
                    {
                        cacheProperties = justAuthProperties.getCache();
                    }
                    
    
                    GitEggRedisStateCache gitEggRedisStateCache =
                            new GitEggRedisStateCache(redisTemplate, cacheProperties, enable);
                    
                    // 组装多租户的第三方配置信息key
                    String authSourceKey = AuthConstant.SOCIAL_TENANT_SOURCE_KEY;
                    if (enable) {
                        authSourceKey += GitEggAuthUtils.getTenantId();
                    } else {
                        authSourceKey = AuthConstant.SOCIAL_SOURCE_KEY;
                    }
                    // 获取具体的第三方配置信息
                    String sourceAuthStr = (String)redisTemplate.opsForHash().get(authSourceKey, source.toUpperCase());
                    if (!StringUtils.isEmpty(sourceAuthStr))
                    {
                        // 转为系统配置对象
                        justAuthSource = JsonUtils.jsonToPojo(sourceAuthStr, JustAuthSource.class);
                        authConfig = BeanCopierUtils.copyByClass(justAuthSource, AuthConfig.class);
                        // 组装scopes,因为系统配置的是逗号分割的字符串
                        if (!StringUtils.isEmpty(justAuthSource.getScopes()))
                        {
                            String[] scopes = justAuthSource.getScopes().split(StrUtil.COMMA);
                            authConfig.setScopes(Arrays.asList(scopes));
                        }
                        // 设置proxy
                        if (StrUtil.isAllNotEmpty(justAuthSource.getProxyType(), justAuthSource.getProxyHostName())
                                && null !=  justAuthSource.getProxyPort())
                        {
                            JustAuthProperties.JustAuthProxyConfig proxyConfig = new JustAuthProperties.JustAuthProxyConfig();
                            proxyConfig.setType(justAuthSource.getProxyType());
                            proxyConfig.setHostname(justAuthSource.getProxyHostName());
                            proxyConfig.setPort(justAuthSource.getProxyPort());
                            if (null != proxyConfig) {
                                HttpConfig httpConfig = HttpConfig.builder().timeout(justAuthSource.getProxyPort()).proxy(new Proxy(Proxy.Type.valueOf(proxyConfig.getType()), new InetSocketAddress(proxyConfig.getHostname(), proxyConfig.getPort()))).build();
                                if (null != justAuthConfig.getHttpTimeout())
                                {
                                    httpConfig.setTimeout(justAuthConfig.getHttpTimeout());
                                }
                                authConfig.setHttpConfig(httpConfig);
                            }
                        }
                        // 组装好配置后,从配置生成request,判断是默认的第三方登录还是自定义第三方登录
                        if (SourceTypeEnum.DEFAULT.key.equals(justAuthSource.getSourceType()))
                        {
                            tenantIdAuthRequest = this.getDefaultRequest(source, authConfig, gitEggRedisStateCache);
                        }
                        else if (!StringUtils.isEmpty(justAuthConfig.getEnumClass()) && SourceTypeEnum.CUSTOM.key.equals(justAuthSource.getSourceType()))
                        {
                            try {
                                Class enumConfigClass = Class.forName(justAuthConfig.getEnumClass());
                                tenantIdAuthRequest = this.getExtendRequest(enumConfigClass, source, (ExtendProperties.ExtendRequestConfig) authConfig, gitEggRedisStateCache);
                            } catch (ClassNotFoundException e) {
                                log.error("初始化自定义第三方登录时发生异常:{}", e);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("获取第三方登录时发生异常:{}", e);
            }
        }
        
        if (null == tenantIdAuthRequest)
        {
            tenantIdAuthRequest =  authRequestFactory.get(source);
        }

        return tenantIdAuthRequest;
    }
    
    /**
     * 获取单个的request
     * @param source
     * @return
     */
    private AuthRequest getDefaultRequest(String source, AuthConfig authConfig, GitEggRedisStateCache gitEggRedisStateCache) {
        AuthDefaultSource authDefaultSource;
        try {
            authDefaultSource = EnumUtil.fromString(AuthDefaultSource.class, source.toUpperCase());
        } catch (IllegalArgumentException var4) {
            return null;
        }
        
        // 从缓存获取租户单独配置
        switch(authDefaultSource) {
            case GITHUB:
                return new AuthGithubRequest(authConfig, gitEggRedisStateCache);
            case WEIBO:
                return new AuthWeiboRequest(authConfig, gitEggRedisStateCache);
            case GITEE:
                return new AuthGiteeRequest(authConfig, gitEggRedisStateCache);
            case DINGTALK:
                return new AuthDingTalkRequest(authConfig, gitEggRedisStateCache);
            case DINGTALK_ACCOUNT:
                return new AuthDingTalkAccountRequest(authConfig, gitEggRedisStateCache);
            case BAIDU:
                return new AuthBaiduRequest(authConfig, gitEggRedisStateCache);
            case CSDN:
                return new AuthCsdnRequest(authConfig, gitEggRedisStateCache);
            case CODING:
                return new AuthCodingRequest(authConfig, gitEggRedisStateCache);
            case OSCHINA:
                return new AuthOschinaRequest(authConfig, gitEggRedisStateCache);
            case ALIPAY:
                return new AuthAlipayRequest(authConfig, gitEggRedisStateCache);
            case QQ:
                return new AuthQqRequest(authConfig, gitEggRedisStateCache);
            case WECHAT_OPEN:
                return new AuthWeChatOpenRequest(authConfig, gitEggRedisStateCache);
            case WECHAT_MP:
                return new AuthWeChatMpRequest(authConfig, gitEggRedisStateCache);
            case WECHAT_ENTERPRISE:
                return new AuthWeChatEnterpriseQrcodeRequest(authConfig, gitEggRedisStateCache);
            case WECHAT_ENTERPRISE_WEB:
                return new AuthWeChatEnterpriseWebRequest(authConfig, gitEggRedisStateCache);
            case TAOBAO:
                return new AuthTaobaoRequest(authConfig, gitEggRedisStateCache);
            case GOOGLE:
                return new AuthGoogleRequest(authConfig, gitEggRedisStateCache);
            case FACEBOOK:
                return new AuthFacebookRequest(authConfig, gitEggRedisStateCache);
            case DOUYIN:
                return new AuthDouyinRequest(authConfig, gitEggRedisStateCache);
            case LINKEDIN:
                return new AuthLinkedinRequest(authConfig, gitEggRedisStateCache);
            case MICROSOFT:
                return new AuthMicrosoftRequest(authConfig, gitEggRedisStateCache);
            case MI:
                return new AuthMiRequest(authConfig, gitEggRedisStateCache);
            case TOUTIAO:
                return new AuthToutiaoRequest(authConfig, gitEggRedisStateCache);
            case TEAMBITION:
                return new AuthTeambitionRequest(authConfig, gitEggRedisStateCache);
            case RENREN:
                return new AuthRenrenRequest(authConfig, gitEggRedisStateCache);
            case PINTEREST:
                return new AuthPinterestRequest(authConfig, gitEggRedisStateCache);
            case STACK_OVERFLOW:
                return new AuthStackOverflowRequest(authConfig, gitEggRedisStateCache);
            case HUAWEI:
                return new AuthHuaweiRequest(authConfig, gitEggRedisStateCache);
            case GITLAB:
                return new AuthGitlabRequest(authConfig, gitEggRedisStateCache);
            case KUJIALE:
                return new AuthKujialeRequest(authConfig, gitEggRedisStateCache);
            case ELEME:
                return new AuthElemeRequest(authConfig, gitEggRedisStateCache);
            case MEITUAN:
                return new AuthMeituanRequest(authConfig, gitEggRedisStateCache);
            case TWITTER:
                return new AuthTwitterRequest(authConfig, gitEggRedisStateCache);
            case FEISHU:
                return new AuthFeishuRequest(authConfig, gitEggRedisStateCache);
            case JD:
                return new AuthJdRequest(authConfig, gitEggRedisStateCache);
            case ALIYUN:
                return new AuthAliyunRequest(authConfig, gitEggRedisStateCache);
            case XMLY:
                return new AuthXmlyRequest(authConfig, gitEggRedisStateCache);
            case AMAZON:
                return new AuthAmazonRequest(authConfig, gitEggRedisStateCache);
            case SLACK:
                return new AuthSlackRequest(authConfig, gitEggRedisStateCache);
            case LINE:
                return new AuthLineRequest(authConfig, gitEggRedisStateCache);
            case OKTA:
                return new AuthOktaRequest(authConfig, gitEggRedisStateCache);
            default:
                return null;
        }
    }
    
    
    private AuthRequest getExtendRequest(Class clazz, String source, ExtendProperties.ExtendRequestConfig extendRequestConfig, GitEggRedisStateCache gitEggRedisStateCache) {
        String upperSource = source.toUpperCase();
        try {
            EnumUtil.fromString(clazz, upperSource);
        } catch (IllegalArgumentException var8) {
            return null;
        }
        if (extendRequestConfig != null) {
            Class<? extends AuthRequest> requestClass = extendRequestConfig.getRequestClass();
            if (requestClass != null) {
                return (AuthRequest) ReflectUtil.newInstance(requestClass, new Object[]{extendRequestConfig, gitEggRedisStateCache});
            }
        }
        return null;
    }
}

未完,因篇幅限制20000字,剩余内容请看下一章: SpringCloud微服务实战——搭建企业级开发框架(四十一):集成JustAuth实现通用第三方登录功能【二】

GitEgg-Cloud是一款基于SpringCloud整合搭建的企业级微服务应用开发框架,开源项目地址:

Gitee: https://gitee.com/wmz1930/GitEgg

GitHub: https://github.com/wmz1930/GitEgg

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。