diff --git a/eiam-authentication/eiam-authentication-all/pom.xml b/eiam-authentication/eiam-authentication-all/pom.xml
index 315402fa..04b5c4af 100644
--- a/eiam-authentication/eiam-authentication-all/pom.xml
+++ b/eiam-authentication/eiam-authentication-all/pom.xml
@@ -57,6 +57,12 @@
eiam-authentication-wechat
${project.version}
+
+
+ cn.topiam
+ eiam-authentication-github
+ ${project.version}
+
cn.topiam
diff --git a/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderCategory.java b/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderCategory.java
index 94914308..84dbb045 100644
--- a/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderCategory.java
+++ b/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderCategory.java
@@ -35,9 +35,11 @@ public enum IdentityProviderCategory implements BaseEnum {
/**
* 社交
*/
- social("social", "社交", Lists.newArrayList(
- IdentityProviderType.QQ,
- IdentityProviderType.WECHAT_QR)),
+ social("social", "社交",
+ Lists.newArrayList(
+ IdentityProviderType.QQ,
+ IdentityProviderType.WECHAT_QR,
+ IdentityProviderType.GITHUB)),
/**
* 企业
*/
diff --git a/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderType.java b/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderType.java
index 239a196c..bef0fcd7 100644
--- a/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderType.java
+++ b/eiam-authentication/eiam-authentication-core/src/main/java/cn/topiam/employee/authentication/common/IdentityProviderType.java
@@ -93,6 +93,13 @@ public final class IdentityProviderType {
*/
public static final IdentityProviderType MAIL = new IdentityProviderType("mail",
"邮件验证码认证", "通过邮件验证码进行身份认证");
+
+ /**
+ * GITHUB认证
+ */
+ public static final IdentityProviderType GITHUB = new IdentityProviderType(
+ "github_oauth", "GITHUB认证", "通过GITHUB进行身份认证");
+
private final String value;
private final String name;
private final String desc;
diff --git a/eiam-authentication/eiam-authentication-github/pom.xml b/eiam-authentication/eiam-authentication-github/pom.xml
new file mode 100644
index 00000000..0cd5689b
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ eiam-authentication
+ cn.topiam
+ 1.0.1-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ eiam-authentication-github
+ jar
+
+
+
+ cn.topiam
+ eiam-authentication-core
+ ${project.version}
+
+
+
\ No newline at end of file
diff --git a/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/GithubIdpOauthConfig.java b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/GithubIdpOauthConfig.java
new file mode 100644
index 00000000..9ce82642
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/GithubIdpOauthConfig.java
@@ -0,0 +1,52 @@
+/*
+ * eiam-authentication-github - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.authentication.github;
+
+import java.io.Serial;
+
+import cn.topiam.employee.authentication.common.config.IdentityProviderConfig;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * GITHUB 认证配置
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2022/4/4 23:58
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GithubIdpOauthConfig extends IdentityProviderConfig {
+ @Serial
+ private static final long serialVersionUID = -6850223527422243176L;
+
+ /**
+ * Client ID
+ */
+ @NotBlank(message = "Client ID 不能为空")
+ private String clientId;
+
+ /**
+ * Client Secret
+ */
+ @NotBlank(message = "Client Secret 不能为空")
+ private String clientSecret;
+}
diff --git a/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/configurer/GithubOauthAuthenticationConfigurer.java b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/configurer/GithubOauthAuthenticationConfigurer.java
new file mode 100644
index 00000000..89c6ad06
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/configurer/GithubOauthAuthenticationConfigurer.java
@@ -0,0 +1,100 @@
+/*
+ * eiam-authentication-github - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.authentication.github.configurer;
+
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractAuthenticationFilterConfigurer;
+import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
+import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.OrRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.util.Assert;
+
+import cn.topiam.employee.authentication.common.service.UserIdpService;
+import cn.topiam.employee.authentication.github.filter.GithubOAuth2AuthorizationRequestRedirectFilter;
+import cn.topiam.employee.authentication.github.filter.GithubOAuth2LoginAuthenticationFilter;
+import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
+
+/**
+ * 认证配置
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2021/9/10 22:58
+ */
+public final class GithubOauthAuthenticationConfigurer extends
+ AbstractAuthenticationFilterConfigurer {
+
+ private final IdentityProviderRepository identityProviderRepository;
+ private final UserIdpService userIdpService;
+
+ GithubOauthAuthenticationConfigurer(IdentityProviderRepository identityProviderRepository,
+ UserIdpService userIdpService) {
+ Assert.notNull(identityProviderRepository, "identityProviderRepository must not be null");
+ Assert.notNull(userIdpService, "userIdpService must not be null");
+ this.identityProviderRepository = identityProviderRepository;
+ this.userIdpService = userIdpService;
+ }
+
+ /**
+ * Create the {@link RequestMatcher} given a loginProcessingUrl
+ *
+ * @param loginProcessingUrl creates the {@link RequestMatcher} based upon the
+ * loginProcessingUrl
+ * @return the {@link RequestMatcher} to use based upon the loginProcessingUrl
+ */
+ @Override
+ protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
+ return new AntPathRequestMatcher(loginProcessingUrl);
+ }
+
+ @Override
+ public void init(HttpSecurity http) throws Exception {
+ //设置登录成功失败处理器
+ //Github扫码登录认证
+ GithubOAuth2LoginAuthenticationFilter loginAuthenticationFilter = new GithubOAuth2LoginAuthenticationFilter(
+ identityProviderRepository, userIdpService);
+ this.setAuthenticationFilter(loginAuthenticationFilter);
+ //处理URL
+ super.loginProcessingUrl(
+ GithubOAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
+ super.init(http);
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ //GITHUB请求重定向
+ GithubOAuth2AuthorizationRequestRedirectFilter requestRedirectFilter = new GithubOAuth2AuthorizationRequestRedirectFilter(
+ identityProviderRepository);
+ http.addFilterBefore(requestRedirectFilter, OAuth2AuthorizationRequestRedirectFilter.class);
+ http.addFilterBefore(this.getAuthenticationFilter(), OAuth2LoginAuthenticationFilter.class);
+ super.configure(http);
+ }
+
+ public RequestMatcher getRequestMatcher() {
+ return new OrRequestMatcher(
+ GithubOAuth2AuthorizationRequestRedirectFilter.getRequestMatcher(),
+ GithubOAuth2LoginAuthenticationFilter.getRequestMatcher());
+ }
+
+ public static GithubOauthAuthenticationConfigurer github(IdentityProviderRepository identityProviderRepository,
+ UserIdpService userIdpService) {
+ return new GithubOauthAuthenticationConfigurer(identityProviderRepository, userIdpService);
+ }
+
+}
diff --git a/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/constant/GithubAuthenticationConstants.java b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/constant/GithubAuthenticationConstants.java
new file mode 100644
index 00000000..a33565c9
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/constant/GithubAuthenticationConstants.java
@@ -0,0 +1,40 @@
+/*
+ * eiam-authentication-github - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.authentication.github.constant;
+
+/**
+ * GITHUB
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2023/8/16 22:19
+ */
+public final class GithubAuthenticationConstants {
+ /**
+ * 获取授权码地址
+ */
+ public static final String URL_AUTHORIZE = "https://github.com/login/oauth/authorize";
+ /**
+ * 获取令牌地址
+ */
+ public static final String URL_GET_ACCESS_TOKEN = "https://github.com/login/oauth/access_token";
+ /**
+ * 获取用户信息的地址
+ */
+ public static final String URL_GET_USER_INFO = "https://api.github.com/user";
+
+}
diff --git a/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2AuthorizationRequestRedirectFilter.java b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2AuthorizationRequestRedirectFilter.java
new file mode 100644
index 00000000..e0d0b604
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2AuthorizationRequestRedirectFilter.java
@@ -0,0 +1,138 @@
+/*
+ * eiam-authentication-github - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.authentication.github.filter;
+
+import java.io.IOException;
+import java.util.Base64;
+import java.util.Map;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpMethod;
+import org.springframework.lang.NonNull;
+import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
+import org.springframework.security.crypto.keygen.StringKeyGenerator;
+import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
+import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.util.Assert;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import com.alibaba.fastjson2.JSONObject;
+
+import cn.topiam.employee.authentication.github.GithubIdpOauthConfig;
+import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
+import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import static cn.topiam.employee.authentication.common.IdentityProviderType.GITHUB;
+import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.PROVIDER_CODE;
+import static cn.topiam.employee.authentication.github.constant.GithubAuthenticationConstants.URL_AUTHORIZE;
+import static cn.topiam.employee.authentication.github.filter.GithubOAuth2LoginAuthenticationFilter.getLoginUrl;
+
+/**
+ * 微信扫码登录请求重定向过滤器
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2022/6/20 21:22
+ */
+@SuppressWarnings("ALL")
+public class GithubOAuth2AuthorizationRequestRedirectFilter extends OncePerRequestFilter {
+
+ private final Logger logger = LoggerFactory
+ .getLogger(GithubOAuth2AuthorizationRequestRedirectFilter.class);
+
+ /**
+ * AntPathRequestMatcher
+ */
+ public static final AntPathRequestMatcher GITHUB_REQUEST_MATCHER = new AntPathRequestMatcher(
+ GITHUB.getAuthorizationPathPrefix() + "/" + "{" + PROVIDER_CODE + "}",
+ HttpMethod.GET.name());
+
+ /**
+ * 重定向策略
+ */
+ private final RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy();
+
+ /**
+ * 认证请求存储库
+ */
+ private final AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
+
+ private static final StringKeyGenerator DEFAULT_STATE_GENERATOR = new Base64StringKeyGenerator(
+ Base64.getUrlEncoder());
+ private final IdentityProviderRepository identityProviderRepository;
+
+ public GithubOAuth2AuthorizationRequestRedirectFilter(IdentityProviderRepository identityProviderRepository) {
+ this.identityProviderRepository = identityProviderRepository;
+ }
+
+ @Override
+ protected void doFilterInternal(@NonNull HttpServletRequest request,
+ @NonNull HttpServletResponse response,
+ @NonNull FilterChain filterChain) throws IOException,
+ ServletException {
+ RequestMatcher.MatchResult matcher = GITHUB_REQUEST_MATCHER.matcher(request);
+ if (!matcher.isMatch()) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+ Map variables = matcher.getVariables();
+ String providerCode = variables.get(PROVIDER_CODE);
+ Optional optional = identityProviderRepository
+ .findByCodeAndEnabledIsTrue(providerCode);
+ if (optional.isEmpty()) {
+ throw new NullPointerException("未查询到身份提供商信息");
+ }
+ IdentityProviderEntity entity = optional.get();
+ GithubIdpOauthConfig config = JSONObject.parseObject(entity.getConfig(),
+ GithubIdpOauthConfig.class);
+ Assert.notNull(config, "GITHUB登录配置不能为空");
+ //构建授权请求
+ OAuth2AuthorizationRequest.Builder builder = OAuth2AuthorizationRequest.authorizationCode()
+ .clientId(config.getClientId()).authorizationUri(URL_AUTHORIZE)
+ .redirectUri(getLoginUrl(optional.get().getCode()))
+ .state(DEFAULT_STATE_GENERATOR.generateKey());
+ builder.parameters(parameters -> {
+ parameters.put(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2ParameterNames.CODE);
+ });
+ this.sendRedirectForAuthorization(request, response, builder.build());
+ }
+
+ private void sendRedirectForAuthorization(HttpServletRequest request,
+ HttpServletResponse response,
+ OAuth2AuthorizationRequest authorizationRequest) throws IOException {
+ this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request,
+ response);
+ this.authorizationRedirectStrategy.sendRedirect(request, response,
+ authorizationRequest.getAuthorizationRequestUri());
+ }
+
+ public static RequestMatcher getRequestMatcher() {
+ return GITHUB_REQUEST_MATCHER;
+ }
+}
diff --git a/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2LoginAuthenticationFilter.java b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2LoginAuthenticationFilter.java
new file mode 100644
index 00000000..0d60f27a
--- /dev/null
+++ b/eiam-authentication/eiam-authentication-github/src/main/java/cn/topiam/employee/authentication/github/filter/GithubOAuth2LoginAuthenticationFilter.java
@@ -0,0 +1,184 @@
+/*
+ * eiam-authentication-github - Employee Identity and Access Management
+ * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package cn.topiam.employee.authentication.github.filter;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
+import org.springframework.http.*;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
+import org.springframework.security.oauth2.core.OAuth2Error;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
+import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.web.client.RestTemplate;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.google.common.collect.Lists;
+
+import cn.topiam.employee.authentication.common.authentication.IdpUserDetails;
+import cn.topiam.employee.authentication.common.filter.AbstractIdpAuthenticationProcessingFilter;
+import cn.topiam.employee.authentication.common.service.UserIdpService;
+import cn.topiam.employee.authentication.github.GithubIdpOauthConfig;
+import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
+import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
+import cn.topiam.employee.core.help.ServerHelp;
+import cn.topiam.employee.support.exception.TopIamException;
+import cn.topiam.employee.support.trace.TraceUtils;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import static cn.topiam.employee.authentication.common.IdentityProviderType.GITHUB;
+import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.*;
+import static cn.topiam.employee.authentication.github.constant.GithubAuthenticationConstants.*;
+
+/**
+ * GITHUB登录
+ *
+ * @author TopIAM
+ * Created by support@topiam.cn on 2021/12/8 21:11
+ */
+@SuppressWarnings({ "AlibabaClassNamingShouldBeCamel", "DuplicatedCode" })
+public class GithubOAuth2LoginAuthenticationFilter extends
+ AbstractIdpAuthenticationProcessingFilter {
+ final String ERROR_CODE = "error";
+ public final static String DEFAULT_FILTER_PROCESSES_URI = GITHUB
+ .getLoginPathPrefix() + "/" + "{" + PROVIDER_CODE + "}";
+ public static final AntPathRequestMatcher REQUEST_MATCHER = new AntPathRequestMatcher(
+ DEFAULT_FILTER_PROCESSES_URI, HttpMethod.GET.name());
+
+ /**
+ * Creates a new instance
+ *
+ * @param identityProviderRepository the {@link IdentityProviderRepository}
+ * @param userIdpService {@link UserIdpService}
+ */
+ public GithubOAuth2LoginAuthenticationFilter(IdentityProviderRepository identityProviderRepository,
+ UserIdpService userIdpService) {
+ super(DEFAULT_FILTER_PROCESSES_URI, userIdpService, identityProviderRepository);
+ }
+
+ /**
+ * GITHUB认证
+ *
+ * @param request {@link HttpServletRequest}
+ * @param response {@link HttpServletRequest}
+ * @return {@link HttpServletRequest}
+ * @throws AuthenticationException {@link AuthenticationException} AuthenticationException
+ */
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request,
+ HttpServletResponse response) throws AuthenticationException,
+ IOException {
+ OAuth2AuthorizationRequest authorizationRequest = getOauth2AuthorizationRequest(request,
+ response);
+ TraceUtils.put(UUID.randomUUID().toString());
+ RequestMatcher.MatchResult matcher = REQUEST_MATCHER.matcher(request);
+ Map variables = matcher.getVariables();
+ String providerCode = variables.get(PROVIDER_CODE);
+ String providerId = getIdentityProviderId(providerCode);
+ //code
+ String code = request.getParameter(OAuth2ParameterNames.CODE);
+ if (StringUtils.isEmpty(code)) {
+ OAuth2Error oauth2Error = new OAuth2Error(INVALID_CODE_PARAMETER_ERROR_CODE);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+ // state
+ String state = request.getParameter(OAuth2ParameterNames.STATE);
+ if (StringUtils.isEmpty(state)) {
+ OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+ if (!authorizationRequest.getState().equals(state)) {
+ OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+ //获取身份提供商
+ IdentityProviderEntity provider = getIdentityProviderEntity(providerCode);
+ GithubIdpOauthConfig config = JSONObject.parseObject(provider.getConfig(),
+ GithubIdpOauthConfig.class);
+ if (Objects.isNull(config)) {
+ logger.error("未查询到GITHUB登录配置");
+ //无效身份提供商
+ OAuth2Error oauth2Error = new OAuth2Error(INVALID_IDP_CONFIG);
+ throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
+ }
+ //获取access token
+ HashMap param = new HashMap<>(16);
+ param.put(OAuth2ParameterNames.CLIENT_ID, config.getClientId().trim());
+ param.put(OAuth2ParameterNames.CLIENT_SECRET, config.getClientSecret().trim());
+ param.put(OAuth2ParameterNames.CODE, code.trim());
+ param.put(OAuth2ParameterNames.REDIRECT_URI, getLoginUrl(provider.getCode()));
+ JSONObject result = request(URL_GET_ACCESS_TOKEN, HttpMethod.POST, null, param);
+ if (Objects.nonNull(result.getString(ERROR_CODE))) {
+ logger.error("获取access_token发生错误: {}" + result.toJSONString());
+ throw new TopIamException("获取access_token发生错误: " + result.toJSONString());
+ }
+ // 获取id信息
+ result = request(URL_GET_USER_INFO, HttpMethod.GET,
+ result.getString(OAuth2ParameterNames.TOKEN_TYPE) + " "
+ + result.getString(
+ OAuth2ParameterNames.ACCESS_TOKEN),
+ param);
+ if (!Objects.isNull(result.getString(ERROR_CODE))) {
+ logger.error("获取GITHUB用户OpenID发生错误: {}" + result.toJSONString());
+ throw new TopIamException("获取GITHUB用户OpenID发生错误: " + result.toJSONString());
+ }
+ // 返回
+ String id = result.getString("id");
+ IdpUserDetails idpUserDetails = IdpUserDetails.builder().openId(id).providerType(GITHUB)
+ .providerCode(providerCode).providerId(providerId).build();
+ return attemptAuthentication(request, response, idpUserDetails);
+
+ }
+
+ @Nullable
+ private static JSONObject request(String url, HttpMethod method, String authorization,
+ HashMap param) {
+ RestTemplate client = new RestTemplate();
+ HttpHeaders headers = new HttpHeaders();
+ headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ if (StringUtils.isNotBlank(authorization)) {
+ headers.set("Authorization", authorization);
+ }
+ HttpEntity requestEntity = new HttpEntity(param, headers);
+ ResponseEntity responseEntity = client.exchange(url, method, requestEntity,
+ String.class);
+ return JSON.parseObject(responseEntity.getBody());
+ }
+
+ public static String getLoginUrl(String providerId) {
+ String url = ServerHelp.getPortalPublicBaseUrl() + "/" + GITHUB.getLoginPathPrefix() + "/"
+ + providerId;
+ return url.replaceAll("(?.
*/
-package cn.topiam.employee.authentication.qq;
\ No newline at end of file
+package cn.topiam.employee.authentication.github;
\ No newline at end of file
diff --git a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/constant/QqAuthenticationConstants.java b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/constant/QqAuthenticationConstants.java
index bd85aaeb..ea6cf93b 100644
--- a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/constant/QqAuthenticationConstants.java
+++ b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/constant/QqAuthenticationConstants.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-package cn.topiam.employee.portal.idp.qq.constant;
+package cn.topiam.employee.authentication.qq.constant;
/**
* 企业微信
diff --git a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2AuthorizationRequestRedirectFilter.java b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2AuthorizationRequestRedirectFilter.java
index f0d317cd..5aab8905 100644
--- a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2AuthorizationRequestRedirectFilter.java
+++ b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2AuthorizationRequestRedirectFilter.java
@@ -51,8 +51,8 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import static cn.topiam.employee.authentication.common.IdentityProviderType.QQ;
import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.PROVIDER_CODE;
+import static cn.topiam.employee.authentication.qq.constant.QqAuthenticationConstants.URL_AUTHORIZE;
import static cn.topiam.employee.authentication.qq.filter.QqOAuth2LoginAuthenticationFilter.getLoginUrl;
-import static cn.topiam.employee.portal.idp.qq.constant.QqAuthenticationConstants.URL_AUTHORIZE;
/**
* 微信扫码登录请求重定向过滤器
diff --git a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2LoginAuthenticationFilter.java b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2LoginAuthenticationFilter.java
index 149483dd..e89d466c 100644
--- a/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2LoginAuthenticationFilter.java
+++ b/eiam-authentication/eiam-authentication-qq/src/main/java/cn/topiam/employee/authentication/qq/filter/QqOAuth2LoginAuthenticationFilter.java
@@ -55,8 +55,8 @@ import static com.nimbusds.oauth2.sdk.GrantType.AUTHORIZATION_CODE;
import static cn.topiam.employee.authentication.common.IdentityProviderType.QQ;
import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.*;
-import static cn.topiam.employee.portal.idp.qq.constant.QqAuthenticationConstants.URL_GET_ACCESS_TOKEN;
-import static cn.topiam.employee.portal.idp.qq.constant.QqAuthenticationConstants.URL_GET_OPEN_ID;
+import static cn.topiam.employee.authentication.qq.constant.QqAuthenticationConstants.URL_GET_ACCESS_TOKEN;
+import static cn.topiam.employee.authentication.qq.constant.QqAuthenticationConstants.URL_GET_OPEN_ID;
/**
* QQ登录
diff --git a/eiam-authentication/pom.xml b/eiam-authentication/pom.xml
index 6c0feb75..4f08bcd8 100644
--- a/eiam-authentication/pom.xml
+++ b/eiam-authentication/pom.xml
@@ -42,6 +42,7 @@
eiam-authentication-all
eiam-authentication-mail
eiam-authentication-sms
+ eiam-authentication-github
diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/Config.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/Config.tsx
index 95e91284..c87bf057 100644
--- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/Config.tsx
+++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/Config.tsx
@@ -23,6 +23,7 @@ import FeiShuScanCodeConfig from './FeiShuScanCodeConfig';
import QqOauthConfig from './QqOauthConfig';
import WeChatScanCode from './WeChatScanCodeConfig';
import WeWorkScanCode from './WeWorkScanCodeConfig';
+import GithubOauthConfig from './GithubOauthConfig';
import { useIntl } from '@umijs/max';
/**
@@ -43,6 +44,7 @@ const Config = (props: { type: IdentityProviderType | string; isCreate?: boolean
{type === IdentityProviderType.dingtalk_oauth && }
{type === IdentityProviderType.qq && }
{type === IdentityProviderType.feishu_oauth && }
+ {type === IdentityProviderType.github && }
.
+ */
+import { ProFormText } from '@ant-design/pro-components';
+import CallbackUrl from './CallbackUrl';
+import { useIntl } from '@umijs/max';
+
+/**
+ * Github Oauth 登录
+ *
+ * @constructor
+ */
+const QqOauthConfig = (props: { isCreate: boolean }) => {
+ const { isCreate } = props;
+ const intl = useIntl();
+
+ return (
+ <>
+
+
+ {!isCreate && }
+ >
+ );
+};
+export default QqOauthConfig;
diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/CreateModal/CreateModal.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/CreateModal/CreateModal.tsx
index 20a4b466..536fac4f 100644
--- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/CreateModal/CreateModal.tsx
+++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/CreateModal/CreateModal.tsx
@@ -121,6 +121,12 @@ export default (props: CreateDrawerProps) => {
id: 'pages.authn.identity_provider.create_modal.form.type.qq',
}),
},
+ {
+ value: IdentityProviderType.github,
+ label: intl.formatMessage({
+ id: 'pages.authn.identity_provider.create_modal.form.type.github',
+ }),
+ },
]}
/>
>
diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/constant.ts b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/constant.ts
index f33b8111..6c00da07 100644
--- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/constant.ts
+++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/constant.ts
@@ -36,6 +36,7 @@ export enum IdentityProviderType {
//社交
qq = 'qq_oauth',
wechat_qr = 'wechat_qr',
+ github = 'github_oauth',
}
/**
diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/locales/zh-CN.ts b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/locales/zh-CN.ts
index e8b3755a..252d21b2 100644
--- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/locales/zh-CN.ts
+++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/locales/zh-CN.ts
@@ -38,6 +38,7 @@ export default {
'pages.authn.identity_provider.create_modal.form.type.rule.0.message': '请选择认证提供商',
'pages.authn.identity_provider.create_modal.form.type.wechat_qr': '微信开放平台扫码认证',
'pages.authn.identity_provider.create_modal.form.type.qq': 'QQ认证',
+ 'pages.authn.identity_provider.create_modal.form.type.github': 'Github认证',
'pages.authn.identity_provider.create_modal.form.type.dingtalk_oauth': '钉钉认证',
'pages.authn.identity_provider.create_modal.form.type.dingtalk_qr': '钉钉扫码认证',
'pages.authn.identity_provider.create_modal.form.type.feishu_oauth': '飞书认证',
@@ -75,4 +76,8 @@ export default {
'pages.authn.identity_provider.config.wework_scan_code.app_secret.placeholder':
'请输入获取的Secret',
'pages.authn.identity_provider.add-success-content': '请复制以下链接访问门户端',
+ 'pages.authn.identity_provider.config.github_oauth.client_id.placeholder': '请填写Client ID',
+ 'pages.authn.identity_provider.config.github_oauth.client_secret.placeholder': '请填写Client Secret',
+ 'pages.authn.identity_provider.config.github_oauth.client_id.extra': 'GitHub应用的Client ID',
+ 'pages.authn.identity_provider.config.github_oauth.client_secret.extra': 'GitHub应用生成的Client secret',
};
diff --git a/eiam-console/src/main/java/cn/topiam/employee/console/converter/authn/IdentityProviderConverter.java b/eiam-console/src/main/java/cn/topiam/employee/console/converter/authn/IdentityProviderConverter.java
index 4cf8553a..e7c55c4a 100644
--- a/eiam-console/src/main/java/cn/topiam/employee/console/converter/authn/IdentityProviderConverter.java
+++ b/eiam-console/src/main/java/cn/topiam/employee/console/converter/authn/IdentityProviderConverter.java
@@ -39,6 +39,7 @@ import cn.topiam.employee.authentication.common.config.IdentityProviderConfig;
import cn.topiam.employee.authentication.dingtalk.DingTalkIdpOauthConfig;
import cn.topiam.employee.authentication.dingtalk.DingTalkIdpScanCodeConfig;
import cn.topiam.employee.authentication.feishu.FeiShuIdpScanCodeConfig;
+import cn.topiam.employee.authentication.github.GithubIdpOauthConfig;
import cn.topiam.employee.authentication.qq.QqIdpOauthConfig;
import cn.topiam.employee.authentication.wechat.WeChatIdpScanCodeConfig;
import cn.topiam.employee.authentication.wechatwork.WeChatWorkIdpScanCodeConfig;
@@ -260,6 +261,9 @@ public interface IdentityProviderConverter {
//飞书认证
} else if (type.equals(FEISHU_OAUTH.value())) {
identityProviderConfig = config.to(FeiShuIdpScanCodeConfig.class);
+ //GITHUB认证
+ } else if (type.equals(GITHUB.value())) {
+ identityProviderConfig = config.to(GithubIdpOauthConfig.class);
} else {
throw new TopIamException("不支持此身份提供商");
}
@@ -311,6 +315,9 @@ public interface IdentityProviderConverter {
if (WECHAT_WEB_PAGE.value().equals(type)) {
return WECHAT_WEB_PAGE;
}
+ if (GITHUB.value().equals(type)) {
+ return GITHUB;
+ }
throw new IllegalArgumentException("未知身份提供商类型");
}
}
diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/PortalSecurityConfiguration.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/PortalSecurityConfiguration.java
index 515b8d52..a57e7438 100644
--- a/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/PortalSecurityConfiguration.java
+++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/PortalSecurityConfiguration.java
@@ -57,6 +57,7 @@ import cn.topiam.employee.authentication.common.service.UserIdpService;
import cn.topiam.employee.authentication.dingtalk.configurer.DingtalkOAuth2AuthenticationConfigurer;
import cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAuthenticationConfigurer;
import cn.topiam.employee.authentication.feishu.configurer.FeiShuScanCodeAuthenticationConfigurer;
+import cn.topiam.employee.authentication.github.configurer.GithubOauthAuthenticationConfigurer;
import cn.topiam.employee.authentication.otp.mail.MailOtpAuthenticationConfigurer;
import cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer;
import cn.topiam.employee.authentication.qq.configurer.QqOauthAuthenticationConfigurer;
@@ -92,6 +93,7 @@ import static cn.topiam.employee.authentication.common.configurer.IdpBindAuthent
import static cn.topiam.employee.authentication.dingtalk.configurer.DingtalkOAuth2AuthenticationConfigurer.dingtalkOAuth2;
import static cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAuthenticationConfigurer.dingtalkScanCode;
import static cn.topiam.employee.authentication.feishu.configurer.FeiShuScanCodeAuthenticationConfigurer.feiShuScanCode;
+import static cn.topiam.employee.authentication.github.configurer.GithubOauthAuthenticationConfigurer.github;
import static cn.topiam.employee.authentication.otp.mail.MailOtpAuthenticationConfigurer.mailOtp;
import static cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer.smsOtp;
import static cn.topiam.employee.authentication.qq.configurer.QqOauthAuthenticationConfigurer.qq;
@@ -164,6 +166,14 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration
requestMatchers.add(chatScanCode.getRequestMatcher());
httpSecurity.apply(chatScanCode);
+ //GITHUB
+ GithubOauthAuthenticationConfigurer github = github(identityProviderRepository, userIdpService)
+ .successHandler(successHandler)
+ .failureHandler(failureHandler)
+ .authenticationDetailsSource(authenticationDetailsSource);
+ requestMatchers.add(github.getRequestMatcher());
+ httpSecurity.apply(github);
+
//企业微信
WeChatWorkScanCodeAuthenticationConfigurer weChatWorkScanCode = weChatWorkScanCode(identityProviderRepository, userIdpService)
.successHandler(successHandler)
diff --git a/eiam-portal/src/main/portal-fe/src/pages/Login/Login.tsx b/eiam-portal/src/main/portal-fe/src/pages/Login/Login.tsx
index 9a9b3c69..e53562c8 100644
--- a/eiam-portal/src/main/portal-fe/src/pages/Login/Login.tsx
+++ b/eiam-portal/src/main/portal-fe/src/pages/Login/Login.tsx
@@ -184,6 +184,21 @@ const Login = () => {
window.open(path, '_self');
};
+ /**
+ * GITHUB
+ *
+ * @param id
+ */
+ const githubOauthOnClick = (id: string) => {
+ const query = queryString.parse(history.location.search);
+ const { redirect_uri } = query as { redirect_uri: string };
+ let path = `/api/v1/authorization/github_oauth/${id}`;
+ if (redirect_uri) {
+ path = `${path}?redirect_uri=${redirect_uri}`;
+ }
+ window.open(path, '_self');
+ };
+
/**
* 提交
*
@@ -478,6 +493,11 @@ const Login = () => {
weiBoOauthOnClick(value.code);
return;
}
+ //GITHUB,跳转页面
+ if (value.type === IDP_TYPE.GITHUB_OAUTH) {
+ githubOauthOnClick(value.code);
+ return;
+ }
//其他方式,跳转页面
else {
setCurrentProvider({