添加Gitee认证源

pull/30/head
smallbun 2023-08-16 19:46:14 +08:00
parent 2980babe1b
commit a01e3f924a
32 changed files with 667 additions and 194 deletions

View File

@ -69,6 +69,12 @@
<artifactId>eiam-authentication-wechatwork</artifactId> <artifactId>eiam-authentication-wechatwork</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<!-- gitee-->
<dependency>
<groupId>cn.topiam</groupId>
<artifactId>eiam-authentication-gitee</artifactId>
<version>${project.version}</version>
</dependency>
<!-- sms--> <!-- sms-->
<dependency> <dependency>
<groupId>cn.topiam</groupId> <groupId>cn.topiam</groupId>

View File

@ -39,6 +39,7 @@ public enum IdentityProviderCategory implements BaseEnum {
Lists.newArrayList( Lists.newArrayList(
IdentityProviderType.QQ, IdentityProviderType.QQ,
IdentityProviderType.WECHAT_QR, IdentityProviderType.WECHAT_QR,
IdentityProviderType.GITHUB,
IdentityProviderType.GITHUB)), IdentityProviderType.GITHUB)),
/** /**
* *

View File

@ -64,6 +64,12 @@ public final class IdentityProviderType {
public static final IdentityProviderType WECHAT_WORK_QR = new IdentityProviderType( public static final IdentityProviderType WECHAT_WORK_QR = new IdentityProviderType(
"wechatwork_qr", "企业微信扫码认证", "通过企业微信同步的用户可使用企业微信扫码登录进行身份认证"); "wechatwork_qr", "企业微信扫码认证", "通过企业微信同步的用户可使用企业微信扫码登录进行身份认证");
/**
* Gitee
*/
public static final IdentityProviderType GITEE_OAUTH = new IdentityProviderType(
"gitee_oauth", "Gitee", "通过Gitee进行身份认证");
/** /**
* QQ * QQ
*/ */

View File

@ -84,7 +84,7 @@ public class IdpUserDetails {
/** /**
* *
*/ */
private final Map<String, String> additionalInfo; private final Map<String, Object> additionalInfo;
public static IdpUserDetailsBuilder builder() { public static IdpUserDetailsBuilder builder() {
return new IdpUserDetailsBuilder(); return new IdpUserDetailsBuilder();
@ -130,7 +130,7 @@ public class IdpUserDetails {
return providerType; return providerType;
} }
public Map<String, String> getAdditionalInfo() { public Map<String, Object> getAdditionalInfo() {
return additionalInfo; return additionalInfo;
} }
@ -138,7 +138,7 @@ public class IdpUserDetails {
final String avatarUrl, final String openId, final String stateCode, final String avatarUrl, final String openId, final String stateCode,
final String unionId, final String providerId, final String providerCode, final String unionId, final String providerId, final String providerCode,
final IdentityProviderType providerType, final IdentityProviderType providerType,
final Map<String, String> additionalInfo) { final Map<String, Object> additionalInfo) {
if (providerId == null) { if (providerId == null) {
throw new NullPointerException("providerId is marked non-null but is null"); throw new NullPointerException("providerId is marked non-null but is null");
} else if (providerType == null) { } else if (providerType == null) {
@ -181,7 +181,7 @@ public class IdpUserDetails {
private IdentityProviderType providerType; private IdentityProviderType providerType;
private Map<String, String> additionalInfo; private Map<String, Object> additionalInfo;
IdpUserDetailsBuilder() { IdpUserDetailsBuilder() {
} }
@ -248,7 +248,7 @@ public class IdpUserDetails {
} }
} }
public IdpUserDetailsBuilder additionalInfo(final Map<String, String> additionalInfo) { public IdpUserDetailsBuilder additionalInfo(final Map<String, Object> additionalInfo) {
this.additionalInfo = additionalInfo; this.additionalInfo = additionalInfo;
return this; return this;
} }

View File

@ -46,6 +46,7 @@ import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository; import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
import cn.topiam.employee.core.help.ServerHelp; import cn.topiam.employee.core.help.ServerHelp;
import cn.topiam.employee.support.util.HttpClientUtils; import cn.topiam.employee.support.util.HttpClientUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -148,7 +149,7 @@ public class FeiShuLoginAuthenticationFilter extends AbstractIdpAuthenticationPr
public static String getLoginUrl(String providerId) { public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + FEISHU_OAUTH.getLoginPathPrefix() + "/" String url = ServerHelp.getPortalPublicBaseUrl() + FEISHU_OAUTH.getLoginPathPrefix() + "/"
+ providerId; + providerId;
return url.replaceAll("(?<!(http:|https:))/+", "/"); return HttpUrlUtils.format(url);
} }
public static RequestMatcher getRequestMatcher() { public static RequestMatcher getRequestMatcher() {

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>eiam-authentication</artifactId>
<groupId>cn.topiam</groupId>
<version>1.0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>eiam-authentication-gitee</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- common -->
<dependency>
<groupId>cn.topiam</groupId>
<artifactId>eiam-authentication-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -1,5 +1,5 @@
/* /*
* eiam-authentication-wechat - Employee Identity and Access Management * eiam-authentication-gitee - Employee Identity and Access Management
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn) * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -15,7 +15,7 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package cn.topiam.employee.authentication.wechat; package cn.topiam.employee.authentication.gitee;
import java.io.Serial; import java.io.Serial;
@ -25,61 +25,27 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/** /**
* * Gitee
* *
* @author TopIAM * @author TopIAM
* Created by support@topiam.cn on 2021/12/9 22:07 21: * Created by support@topiam.cn on 2021/12/9 22:07 21:
*/ */
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class WeChatIdpWebPageConfig extends IdentityProviderConfig { public class GiteeIdpOAuth2Config extends IdentityProviderConfig {
@Serial @Serial
private static final long serialVersionUID = -5831048603320371078L; private static final long serialVersionUID = -5831048603320371078L;
/** /**
* id * id
*/ */
@NotBlank(message = "应用AppId不能为空") @NotBlank(message = "应用clientId不能为空")
private String appId; private String clientId;
/** /**
* Secret * Secret
*/ */
@NotBlank(message = "应用AppId不能为空") @NotBlank(message = "应用clientSecret不能为空")
private String appSecret; private String clientSecret;
/**
*
*/
@NotBlank(message = "授权范围不能为空")
private String scope;
/**
* URI
*/
@NotBlank(message = "重定向URI不能为空")
private String redirectUri;
/**
*
*/
@NotNull(message = "域名校验文件不能为空")
private VerifyFile verifyFile;
@Data
public static class VerifyFile {
/**
*
*/
@NotBlank(message = "域名校验文件名不能为空")
private String name;
/**
*
*/
@NotBlank(message = "域名校验文件内容不能为空")
private String content;
}
} }

View File

@ -0,0 +1,96 @@
/*
* eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.authentication.gitee.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.gitee.filter.GiteeAuthorizationRequestRedirectFilter;
import cn.topiam.employee.authentication.gitee.filter.GiteeLoginAuthenticationFilter;
import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
/**
*
*
* @author TopIAM
* Created by support@topiam.cn on 2021/9/10 22:58
*/
public final class GiteeAuthenticationConfigurer extends
AbstractAuthenticationFilterConfigurer<HttpSecurity, GiteeAuthenticationConfigurer, GiteeLoginAuthenticationFilter> {
private final IdentityProviderRepository identityProviderRepository;
private final UserIdpService userIdpService;
GiteeAuthenticationConfigurer(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 {
//Gitee登录认证
GiteeLoginAuthenticationFilter loginAuthenticationFilter = new GiteeLoginAuthenticationFilter(
identityProviderRepository, userIdpService);
this.setAuthenticationFilter(loginAuthenticationFilter);
//处理URL
super.loginProcessingUrl(GiteeLoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
super.init(http);
}
@Override
public void configure(HttpSecurity http) throws Exception {
//Gitee扫码请求重定向
GiteeAuthorizationRequestRedirectFilter requestRedirectFilter = new GiteeAuthorizationRequestRedirectFilter(
identityProviderRepository);
http.addFilterBefore(requestRedirectFilter, OAuth2AuthorizationRequestRedirectFilter.class);
http.addFilterBefore(this.getAuthenticationFilter(), OAuth2LoginAuthenticationFilter.class);
super.configure(http);
}
public RequestMatcher getRequestMatcher() {
return new OrRequestMatcher(GiteeAuthorizationRequestRedirectFilter.getRequestMatcher(),
GiteeLoginAuthenticationFilter.getRequestMatcher());
}
public static GiteeAuthenticationConfigurer giteeOauth(IdentityProviderRepository identityProviderRepository,
UserIdpService userIdpService) {
return new GiteeAuthenticationConfigurer(identityProviderRepository, userIdpService);
}
}

View File

@ -0,0 +1,35 @@
/*
* eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.authentication.gitee.constant;
/**
* Gitee
*
* @author TopIAM
* Created by support@topiam.cn on 2021/12/9 22:19
*/
public final class GiteeAuthenticationConstants {
public static final String AUTHORIZATION_REQUEST = "https://gitee.com/oauth/authorize";
public static final String ACCESS_TOKEN = "https://gitee.com/oauth/token";
public static final String USER_INFO = "https://gitee.com/api/v5/user";
public static final String ERROR_CODE = "error";
public static final String USER_INFO_SCOPE = "user_info";
public static final String ID = "id";
}

View File

@ -0,0 +1,143 @@
/*
* eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.authentication.gitee.filter;
import java.io.IOException;
import java.util.*;
import org.checkerframework.checker.nullness.qual.Nullable;
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.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 com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cn.topiam.employee.authentication.gitee.GiteeIdpOAuth2Config;
import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
import cn.topiam.employee.support.trace.TraceUtils;
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.GITEE_OAUTH;
import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.PROVIDER_CODE;
import static cn.topiam.employee.authentication.gitee.constant.GiteeAuthenticationConstants.AUTHORIZATION_REQUEST;
import static cn.topiam.employee.authentication.gitee.constant.GiteeAuthenticationConstants.USER_INFO_SCOPE;
/**
* Gitee
*
* @author TopIAM
* Created by support@topiam.cn on 2022/6/20 21:22
*/
@SuppressWarnings("DuplicatedCode")
public class GiteeAuthorizationRequestRedirectFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory
.getLogger(GiteeAuthorizationRequestRedirectFilter.class);
/**
* AntPathRequestMatcher
*/
public static final AntPathRequestMatcher GITEE_REQUEST_MATCHER = new AntPathRequestMatcher(
GITEE_OAUTH.getAuthorizationPathPrefix() + "/" + "{" + PROVIDER_CODE + "}",
HttpMethod.GET.name());
/**
*
*/
private final RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy();
/**
*
*/
private final AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
private static final StringKeyGenerator DEFAULT_STATE_GENERATOR = new Base64StringKeyGenerator(
Base64.getUrlEncoder());
private final IdentityProviderRepository identityProviderRepository;
public GiteeAuthorizationRequestRedirectFilter(IdentityProviderRepository identityProviderRepository) {
this.identityProviderRepository = identityProviderRepository;
}
@Override
protected void doFilterInternal(@NonNull HttpServletRequest request,
@NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws IOException,
ServletException {
RequestMatcher.MatchResult matcher = GITEE_REQUEST_MATCHER.matcher(request);
if (!matcher.isMatch()) {
filterChain.doFilter(request, response);
return;
}
TraceUtils.put(UUID.randomUUID().toString());
Map<String, String> variables = matcher.getVariables();
String providerCode = variables.get(PROVIDER_CODE);
Optional<IdentityProviderEntity> optional = identityProviderRepository
.findByCodeAndEnabledIsTrue(providerCode);
if (optional.isEmpty()) {
throw new NullPointerException("未查询到身份提供商信息");
}
IdentityProviderEntity entity = optional.get();
GiteeIdpOAuth2Config config = JSONObject.parseObject(entity.getConfig(),
GiteeIdpOAuth2Config.class);
Assert.notNull(config, "Gitee 登录配置不能为空");
//构建授权请求
//@formatter:off
HashMap<@Nullable String, @Nullable Object> attributes = Maps.newHashMap();
OAuth2AuthorizationRequest.Builder builder = OAuth2AuthorizationRequest.authorizationCode()
.clientId(config.getClientId())
.scopes(Sets.newHashSet(USER_INFO_SCOPE))
.authorizationUri(AUTHORIZATION_REQUEST)
.redirectUri(GiteeLoginAuthenticationFilter.getLoginUrl(optional.get().getCode()))
.state(DEFAULT_STATE_GENERATOR.generateKey())
.attributes(attributes);
//@formatter:on
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 GITEE_REQUEST_MATCHER;
}
}

View File

@ -0,0 +1,179 @@
/*
* eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.authentication.gitee.filter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
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 com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
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.gitee.GiteeIdpOAuth2Config;
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.util.HttpClientUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import static org.springframework.security.oauth2.core.AuthorizationGrantType.AUTHORIZATION_CODE;
import static org.springframework.security.oauth2.core.OAuth2TokenIntrospectionClaimNames.CLIENT_ID;
import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.CLIENT_SECRET;
import static cn.topiam.employee.authentication.common.IdentityProviderType.*;
import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.*;
import static cn.topiam.employee.authentication.gitee.constant.GiteeAuthenticationConstants.*;
/**
* Gitee
*
* @author TopIAM
* Created by support@topiam.cn on 2021/12/8 21:11
*/
@SuppressWarnings("DuplicatedCode")
public class GiteeLoginAuthenticationFilter extends AbstractIdpAuthenticationProcessingFilter {
public final static String DEFAULT_FILTER_PROCESSES_URI = GITEE_OAUTH
.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 GiteeLoginAuthenticationFilter(IdentityProviderRepository identityProviderRepository,
UserIdpService userIdpService) {
super(DEFAULT_FILTER_PROCESSES_URI, userIdpService, identityProviderRepository);
}
/**
* Gitee
*
* @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);
RequestMatcher.MatchResult matcher = REQUEST_MATCHER.matcher(request);
Map<String, String> variables = matcher.getVariables();
String providerCode = variables.get(PROVIDER_CODE);
String providerId = getIdentityProviderId(providerCode);
//code
String code = request.getParameter(OAuth2ParameterNames.CODE);
if (StringUtils.isEmpty(code)) {
logger.error("Gitee 登录 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)) {
logger.error("Gitee 登录 state 参数不存在,认证失败");
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
if (!authorizationRequest.getState().equals(state)) {
logger.error("Gitee 登录 state 匹配不一致,认证失败");
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
//获取身份提供商
IdentityProviderEntity provider = getIdentityProviderEntity(providerCode);
GiteeIdpOAuth2Config config = JSONObject.parseObject(provider.getConfig(),
GiteeIdpOAuth2Config.class);
if (Objects.isNull(config)) {
logger.error("未查询到 Gitee 登录配置");
//无效身份提供商
OAuth2Error oauth2Error = new OAuth2Error(
AbstractIdpAuthenticationProcessingFilter.INVALID_IDP_CONFIG);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
//获取access token
HashMap<String, String> param = new HashMap<>(16);
param.put(CLIENT_ID, config.getClientId());
param.put(CLIENT_SECRET, config.getClientSecret());
param.put(OAuth2ParameterNames.CODE, code);
param.put(OAuth2ParameterNames.REDIRECT_URI, getLoginUrl(providerCode));
param.put(OAuth2ParameterNames.GRANT_TYPE, AUTHORIZATION_CODE.getValue());
JSONObject result = JSON.parseObject(HttpClientUtils.post(ACCESS_TOKEN, param));
if (result.containsKey(ERROR_CODE)) {
logger.error("获取access_token发生错误: " + result.toJSONString());
throw new TopIamException("获取access_token发生错误: " + result.toJSONString());
}
// 获取user信息
param = new HashMap<>(16);
param.put(OAuth2ParameterNames.ACCESS_TOKEN,
result.getString(OAuth2ParameterNames.ACCESS_TOKEN));
result = JSON.parseObject(HttpClientUtils.get(USER_INFO, param));
if (result.containsKey(ERROR_CODE)) {
logger.error("获取Gitee用户个人信息发生错误: " + result.toJSONString());
throw new TopIamException("获取Gitee用户个人信息发生错误: " + result.toJSONString());
}
// 返回
//@formatter:off
IdpUserDetails idpUserDetails = IdpUserDetails.builder()
.openId(param.get(ID))
.nickName((String) result.get("name"))
.avatarUrl((String) result.get("avatar_uri"))
.email((String) result.get("email"))
.providerCode(providerCode)
.providerId(providerId)
.providerType(GITEE_OAUTH)
.additionalInfo(new HashMap<>(result))
.build();
//@formatter:on
return attemptAuthentication(request, response, idpUserDetails);
}
public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + GITEE_OAUTH.getLoginPathPrefix() + "/"
+ providerId;
return HttpUrlUtils.format(url);
}
public static RequestMatcher getRequestMatcher() {
return REQUEST_MATCHER;
}
}

View File

@ -0,0 +1,18 @@
/*
* eiam-authentication-gitee - 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 <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.authentication.gitee;

View File

@ -24,7 +24,6 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.*; import org.springframework.http.*;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
@ -49,6 +48,7 @@ import cn.topiam.employee.common.repository.authentication.IdentityProviderRepos
import cn.topiam.employee.core.help.ServerHelp; import cn.topiam.employee.core.help.ServerHelp;
import cn.topiam.employee.support.exception.TopIamException; import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.trace.TraceUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -156,7 +156,6 @@ public class GithubOAuth2LoginAuthenticationFilter extends
} }
@Nullable
private static JSONObject request(String url, HttpMethod method, String authorization, private static JSONObject request(String url, HttpMethod method, String authorization,
HashMap<String, String> param) { HashMap<String, String> param) {
RestTemplate client = new RestTemplate(); RestTemplate client = new RestTemplate();
@ -166,7 +165,7 @@ public class GithubOAuth2LoginAuthenticationFilter extends
if (StringUtils.isNotBlank(authorization)) { if (StringUtils.isNotBlank(authorization)) {
headers.set("Authorization", authorization); headers.set("Authorization", authorization);
} }
HttpEntity requestEntity = new HttpEntity(param, headers); HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(param, headers);
ResponseEntity<String> responseEntity = client.exchange(url, method, requestEntity, ResponseEntity<String> responseEntity = client.exchange(url, method, requestEntity,
String.class); String.class);
return JSON.parseObject(responseEntity.getBody()); return JSON.parseObject(responseEntity.getBody());
@ -175,7 +174,7 @@ public class GithubOAuth2LoginAuthenticationFilter extends
public static String getLoginUrl(String providerId) { public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + "/" + GITHUB.getLoginPathPrefix() + "/" String url = ServerHelp.getPortalPublicBaseUrl() + "/" + GITHUB.getLoginPathPrefix() + "/"
+ providerId; + providerId;
return url.replaceAll("(?<!(http:|https:))/+", "/"); return HttpUrlUtils.format(url);
} }
public static RequestMatcher getRequestMatcher() { public static RequestMatcher getRequestMatcher() {

View File

@ -48,6 +48,7 @@ import cn.topiam.employee.core.help.ServerHelp;
import cn.topiam.employee.support.exception.TopIamException; import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.trace.TraceUtils;
import cn.topiam.employee.support.util.HttpClientUtils; import cn.topiam.employee.support.util.HttpClientUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -164,7 +165,7 @@ public class QqOAuth2LoginAuthenticationFilter extends AbstractIdpAuthentication
public static String getLoginUrl(String providerId) { public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + "/" + QQ.getLoginPathPrefix() + "/" String url = ServerHelp.getPortalPublicBaseUrl() + "/" + QQ.getLoginPathPrefix() + "/"
+ providerId; + providerId;
return url.replaceAll("(?<!(http:|https:))/+", "/"); return HttpUrlUtils.format(url);
} }
public static RequestMatcher getRequestMatcher() { public static RequestMatcher getRequestMatcher() {

View File

@ -46,6 +46,7 @@ import cn.topiam.employee.common.repository.authentication.IdentityProviderRepos
import cn.topiam.employee.core.help.ServerHelp; import cn.topiam.employee.core.help.ServerHelp;
import cn.topiam.employee.support.exception.TopIamException; import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.util.HttpClientUtils; import cn.topiam.employee.support.util.HttpClientUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -159,7 +160,7 @@ public class WeChatScanCodeLoginAuthenticationFilter extends
public static String getLoginUrl(String providerId) { public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + WECHAT_QR.getLoginPathPrefix() + "/" String url = ServerHelp.getPortalPublicBaseUrl() + WECHAT_QR.getLoginPathPrefix() + "/"
+ providerId; + providerId;
return url.replaceAll("(?<!(http:|https:))/+", "/"); return HttpUrlUtils.format(url);
} }
public static RequestMatcher getRequestMatcher() { public static RequestMatcher getRequestMatcher() {

View File

@ -50,6 +50,7 @@ import cn.topiam.employee.common.repository.authentication.IdentityProviderRepos
import cn.topiam.employee.core.help.ServerHelp; import cn.topiam.employee.core.help.ServerHelp;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.trace.TraceUtils;
import cn.topiam.employee.support.util.HttpClientUtils; import cn.topiam.employee.support.util.HttpClientUtils;
import cn.topiam.employee.support.util.HttpUrlUtils;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -191,7 +192,7 @@ public class WeChatWorkScanCodeLoginAuthenticationFilter extends
public static String getLoginUrl(String providerId) { public static String getLoginUrl(String providerId) {
String url = ServerHelp.getPortalPublicBaseUrl() + WECHAT_WORK_QR.getLoginPathPrefix() + "/" String url = ServerHelp.getPortalPublicBaseUrl() + WECHAT_WORK_QR.getLoginPathPrefix() + "/"
+ providerId; + providerId;
return url.replaceAll("(?<!(http:|https:))/+", "/"); return HttpUrlUtils.format(url);
} }

View File

@ -43,6 +43,7 @@
<module>eiam-authentication-mail</module> <module>eiam-authentication-mail</module>
<module>eiam-authentication-sms</module> <module>eiam-authentication-sms</module>
<module>eiam-authentication-github</module> <module>eiam-authentication-github</module>
<module>eiam-authentication-gitee</module>
</modules> </modules>
<dependencies> <dependencies>

View File

@ -102,7 +102,7 @@
"eslint": "^8.47.0", "eslint": "^8.47.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^14.0.0", "lint-staged": "^14.0.0",
"prettier": "^3.0.1", "prettier": "^3.0.2",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"umi-presets-pro": "^2.0.3" "umi-presets-pro": "^2.0.3"
}, },

View File

@ -34,6 +34,7 @@ export const ICON_LIST = {
wechatwork_qr: <IconFont name="icon-qiyeweixin" />, wechatwork_qr: <IconFont name="icon-qiyeweixin" />,
feishu_oauth: <IconFont name="icon-feishu" />, feishu_oauth: <IconFont name="icon-feishu" />,
qq_oauth: <IconFont name="icon-qq" />, qq_oauth: <IconFont name="icon-qq" />,
gitee_oauth: <IconFont name="icon-gitee" />,
weibo_oauth: <IconFont name="icon-weibo" />, weibo_oauth: <IconFont name="icon-weibo" />,
github_oauth: <IconFont name="icon-github" />, github_oauth: <IconFont name="icon-github" />,
google_oauth: <IconFont name="icon-google" />, google_oauth: <IconFont name="icon-google" />,

File diff suppressed because one or more lines are too long

View File

@ -24,6 +24,7 @@ import QqOauthConfig from './QqOauthConfig';
import WeChatScanCode from './WeChatScanCodeConfig'; import WeChatScanCode from './WeChatScanCodeConfig';
import WeWorkScanCode from './WeWorkScanCodeConfig'; import WeWorkScanCode from './WeWorkScanCodeConfig';
import GithubOauthConfig from './GithubOauthConfig'; import GithubOauthConfig from './GithubOauthConfig';
import GiteeOauthConfig from './GiteeOauthConfig';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
/** /**
@ -44,6 +45,7 @@ const Config = (props: { type: IdentityProviderType | string; isCreate?: boolean
{type === IdentityProviderType.dingtalk_oauth && <DingTalkOauthConfig isCreate={isCreate} />} {type === IdentityProviderType.dingtalk_oauth && <DingTalkOauthConfig isCreate={isCreate} />}
{type === IdentityProviderType.qq && <QqOauthConfig isCreate={isCreate} />} {type === IdentityProviderType.qq && <QqOauthConfig isCreate={isCreate} />}
{type === IdentityProviderType.feishu_oauth && <FeiShuScanCodeConfig isCreate={isCreate} />} {type === IdentityProviderType.feishu_oauth && <FeiShuScanCodeConfig isCreate={isCreate} />}
{type === IdentityProviderType.gitee && <GiteeOauthConfig isCreate={isCreate} />}
{type === IdentityProviderType.github && <GithubOauthConfig isCreate={isCreate} />} {type === IdentityProviderType.github && <GithubOauthConfig isCreate={isCreate} />}
<ProFormSwitch <ProFormSwitch
name={['displayed']} name={['displayed']}

View File

@ -0,0 +1,55 @@
/*
* eiam-console - 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 <http://www.gnu.org/licenses/>.
*/
import { ProFormText } from '@ant-design/pro-components';
import CallbackUrl from './CallbackUrl';
import { useIntl } from '@umijs/max';
/**
* Gitee Oauth
*
* @constructor
*/
const GiteeOauthConfig = (props: { isCreate: boolean }) => {
const { isCreate } = props;
const intl = useIntl();
return (
<>
<ProFormText
name={['config', 'clientId']}
label="ClientId"
rules={[{ required: true }]}
fieldProps={{ autoComplete: 'off' }}
placeholder={intl.formatMessage({
id: 'pages.authn.identity_provider.config.gitee_oauth.client_id.placeholder',
})}
/>
<ProFormText.Password
rules={[{ required: true }]}
name={['config', 'clientSecret']}
label="ClientSecret"
placeholder={intl.formatMessage({
id: 'pages.authn.identity_provider.config.gitee_oauth.client_secret.placeholder',
})}
fieldProps={{ autoComplete: 'off' }}
/>
{!isCreate && <CallbackUrl />}
</>
);
};
export default GiteeOauthConfig;

View File

@ -127,6 +127,12 @@ export default (props: CreateDrawerProps) => {
id: 'pages.authn.identity_provider.create_modal.form.type.github', id: 'pages.authn.identity_provider.create_modal.form.type.github',
}), }),
}, },
{
value: IdentityProviderType.gitee,
label: intl.formatMessage({
id: 'pages.authn.identity_provider.create_modal.form.type.gitee',
}),
},
]} ]}
/> />
</> </>

View File

@ -35,6 +35,7 @@ export enum IdentityProviderType {
ldap = 'ldap', ldap = 'ldap',
//社交 //社交
qq = 'qq_oauth', qq = 'qq_oauth',
gitee = 'gitee_oauth',
wechat_qr = 'wechat_qr', wechat_qr = 'wechat_qr',
github = 'github_oauth', github = 'github_oauth',
} }

View File

@ -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.rule.0.message': '请选择认证提供商',
'pages.authn.identity_provider.create_modal.form.type.wechat_qr': '微信开放平台扫码认证', '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.qq': 'QQ认证',
'pages.authn.identity_provider.create_modal.form.type.gitee': 'Gitee认证',
'pages.authn.identity_provider.create_modal.form.type.github': 'Github认证', '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_oauth': '钉钉认证',
'pages.authn.identity_provider.create_modal.form.type.dingtalk_qr': '钉钉扫码认证', 'pages.authn.identity_provider.create_modal.form.type.dingtalk_qr': '钉钉扫码认证',
@ -56,7 +57,10 @@ export default {
'pages.authn.identity_provider.config.ding_talk_oauth.app_secret.placeholder': '请填写AppSecret', 'pages.authn.identity_provider.config.ding_talk_oauth.app_secret.placeholder': '请填写AppSecret',
'pages.authn.identity_provider.config.feishu_scan_code.app_id.extra': 'pages.authn.identity_provider.config.feishu_scan_code.app_id.extra':
'在飞书开放平台,开发者后台 -> 企业自建应用,创建企业自建应用', '在飞书开放平台,开发者后台 -> 企业自建应用,创建企业自建应用',
'pages.authn.identity_provider.config.qq_oauth.app_secret.placeholder': '请填写appKey', 'pages.authn.identity_provider.config.qq_oauth.app_id.placeholder': '请填写AppId',
'pages.authn.identity_provider.config.qq_oauth.app_secret.placeholder': '请填写AppKey',
'pages.authn.identity_provider.config.gitee_oauth.client_id.placeholder': '请填写ClientId',
'pages.authn.identity_provider.config.gitee_oauth.client_secret.placeholder': '请填写ClientSecret',
'pages.authn.identity_provider.config.wechat_scan_code.app_id.extra': 'pages.authn.identity_provider.config.wechat_scan_code.app_id.extra':
'微信扫码登录开发申请获取的AppId', '微信扫码登录开发申请获取的AppId',
'pages.authn.identity_provider.config.wechat_scan_code.app_id.placeholder': '请填写获取的AppId', 'pages.authn.identity_provider.config.wechat_scan_code.app_id.placeholder': '请填写获取的AppId',

View File

@ -39,9 +39,9 @@ import cn.topiam.employee.authentication.common.config.IdentityProviderConfig;
import cn.topiam.employee.authentication.dingtalk.DingTalkIdpOauthConfig; import cn.topiam.employee.authentication.dingtalk.DingTalkIdpOauthConfig;
import cn.topiam.employee.authentication.dingtalk.DingTalkIdpScanCodeConfig; import cn.topiam.employee.authentication.dingtalk.DingTalkIdpScanCodeConfig;
import cn.topiam.employee.authentication.feishu.FeiShuIdpScanCodeConfig; import cn.topiam.employee.authentication.feishu.FeiShuIdpScanCodeConfig;
import cn.topiam.employee.authentication.gitee.GiteeIdpOAuth2Config;
import cn.topiam.employee.authentication.github.GithubIdpOauthConfig; import cn.topiam.employee.authentication.github.GithubIdpOauthConfig;
import cn.topiam.employee.authentication.qq.QqIdpOauthConfig; import cn.topiam.employee.authentication.qq.QqIdpOauthConfig;
import cn.topiam.employee.authentication.wechat.WeChatIdpScanCodeConfig;
import cn.topiam.employee.authentication.wechatwork.WeChatWorkIdpScanCodeConfig; import cn.topiam.employee.authentication.wechatwork.WeChatWorkIdpScanCodeConfig;
import cn.topiam.employee.common.entity.authn.IdentityProviderEntity; import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
import cn.topiam.employee.common.entity.authn.QIdentityProviderEntity; import cn.topiam.employee.common.entity.authn.QIdentityProviderEntity;
@ -245,7 +245,7 @@ public interface IdentityProviderConverter {
IdentityProviderConfig identityProviderConfig; IdentityProviderConfig identityProviderConfig;
//微信扫码 //微信扫码
if (type.equals(WECHAT_QR.value())) { if (type.equals(WECHAT_QR.value())) {
identityProviderConfig = config.to(WeChatIdpScanCodeConfig.class); identityProviderConfig = config.to(GiteeIdpOAuth2Config.class);
//钉钉扫码 //钉钉扫码
} else if (type.equals(DINGTALK_QR.value())) { } else if (type.equals(DINGTALK_QR.value())) {
identityProviderConfig = config.to(DingTalkIdpScanCodeConfig.class); identityProviderConfig = config.to(DingTalkIdpScanCodeConfig.class);
@ -264,6 +264,10 @@ public interface IdentityProviderConverter {
//GITHUB认证 //GITHUB认证
} else if (type.equals(GITHUB.value())) { } else if (type.equals(GITHUB.value())) {
identityProviderConfig = config.to(GithubIdpOauthConfig.class); identityProviderConfig = config.to(GithubIdpOauthConfig.class);
}
//Gitee
else if (type.equals(GITEE_OAUTH.value())) {
identityProviderConfig = config.to(GiteeIdpOAuth2Config.class);
} else { } else {
throw new TopIamException("不支持此身份提供商"); throw new TopIamException("不支持此身份提供商");
} }
@ -318,6 +322,9 @@ public interface IdentityProviderConverter {
if (GITHUB.value().equals(type)) { if (GITHUB.value().equals(type)) {
return GITHUB; return GITHUB;
} }
if (GITEE_OAUTH.value().equals(type)) {
return GITEE_OAUTH;
}
throw new IllegalArgumentException("未知身份提供商类型"); throw new IllegalArgumentException("未知身份提供商类型");
} }
} }

View File

@ -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.DingtalkOAuth2AuthenticationConfigurer;
import cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAuthenticationConfigurer; import cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAuthenticationConfigurer;
import cn.topiam.employee.authentication.feishu.configurer.FeiShuScanCodeAuthenticationConfigurer; import cn.topiam.employee.authentication.feishu.configurer.FeiShuScanCodeAuthenticationConfigurer;
import cn.topiam.employee.authentication.gitee.configurer.GiteeAuthenticationConfigurer;
import cn.topiam.employee.authentication.github.configurer.GithubOauthAuthenticationConfigurer; import cn.topiam.employee.authentication.github.configurer.GithubOauthAuthenticationConfigurer;
import cn.topiam.employee.authentication.otp.mail.MailOtpAuthenticationConfigurer; import cn.topiam.employee.authentication.otp.mail.MailOtpAuthenticationConfigurer;
import cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer; import cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer;
@ -93,6 +94,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.DingtalkOAuth2AuthenticationConfigurer.dingtalkOAuth2;
import static cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAuthenticationConfigurer.dingtalkScanCode; 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.feishu.configurer.FeiShuScanCodeAuthenticationConfigurer.feiShuScanCode;
import static cn.topiam.employee.authentication.gitee.configurer.GiteeAuthenticationConfigurer.giteeOauth;
import static cn.topiam.employee.authentication.github.configurer.GithubOauthAuthenticationConfigurer.github; 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.mail.MailOtpAuthenticationConfigurer.mailOtp;
import static cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer.smsOtp; import static cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer.smsOtp;
@ -206,6 +208,15 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration
requestMatchers.add(feiShuScanCode.getRequestMatcher()); requestMatchers.add(feiShuScanCode.getRequestMatcher());
httpSecurity.apply(feiShuScanCode); httpSecurity.apply(feiShuScanCode);
//Gitee
GiteeAuthenticationConfigurer giteeCode = giteeOauth(identityProviderRepository, userIdpService)
.successHandler(successHandler)
.failureHandler(failureHandler)
.authenticationDetailsSource(authenticationDetailsSource);
requestMatchers.add(giteeCode.getRequestMatcher());
httpSecurity.apply(giteeCode);
//RequestMatcher //RequestMatcher
OrRequestMatcher requestMatcher = new OrRequestMatcher(requestMatchers); OrRequestMatcher requestMatcher = new OrRequestMatcher(requestMatchers);
//社交授权请求重定向匹配器 //社交授权请求重定向匹配器

View File

@ -97,7 +97,7 @@
"eslint": "^8.47.0", "eslint": "^8.47.0",
"husky": "^8.0.3", "husky": "^8.0.3",
"lint-staged": "^14.0.0", "lint-staged": "^14.0.0",
"prettier": "^3.0.1", "prettier": "^3.0.2",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"umi-presets-pro": "^2.0.3" "umi-presets-pro": "^2.0.3"
}, },

View File

@ -34,6 +34,7 @@ export const ICON_LIST = {
wechatwork_qr: <IconFont name="icon-qiyeweixin" />, wechatwork_qr: <IconFont name="icon-qiyeweixin" />,
feishu_oauth: <IconFont name="icon-feishu" />, feishu_oauth: <IconFont name="icon-feishu" />,
qq_oauth: <IconFont name="icon-qq" />, qq_oauth: <IconFont name="icon-qq" />,
gitee_oauth: <IconFont name="icon-gitee" />,
weibo_oauth: <IconFont name="icon-weibo" />, weibo_oauth: <IconFont name="icon-weibo" />,
github_oauth: <IconFont name="icon-github" />, github_oauth: <IconFont name="icon-github" />,
google_oauth: <IconFont name="icon-google" />, google_oauth: <IconFont name="icon-google" />,

File diff suppressed because one or more lines are too long

View File

@ -35,6 +35,7 @@ export enum IDP_TYPE {
FEISHU_OAUTH = 'feishu_oauth', FEISHU_OAUTH = 'feishu_oauth',
DINGTALK_OAUTH = 'dingtalk_oauth', DINGTALK_OAUTH = 'dingtalk_oauth',
QQ_OAUTH = 'qq_oauth', QQ_OAUTH = 'qq_oauth',
GITEE_OAUTH = 'gitee_oauth',
GITHUB_OAUTH = 'github_oauth', GITHUB_OAUTH = 'github_oauth',
WEIBO_OAUTH = 'weibo_oauth', WEIBO_OAUTH = 'weibo_oauth',
WECHATWORK_QR = 'wechatwork_qr', WECHATWORK_QR = 'wechatwork_qr',

View File

@ -199,6 +199,21 @@ const Login = () => {
window.open(path, '_self'); window.open(path, '_self');
}; };
/**
* gitee
*
* @param id
*/
const giteeOauthOnClick = (id: string) => {
const query = queryString.parse(history.location.search);
const { redirect_uri } = query as { redirect_uri: string };
let path = `/api/v1/authorization/gitee_oauth/${id}`;
if (redirect_uri) {
path = `${path}?redirect_uri=${redirect_uri}`;
}
window.open(path, '_self');
};
/** /**
* *
* *
@ -493,6 +508,11 @@ const Login = () => {
weiBoOauthOnClick(value.code); weiBoOauthOnClick(value.code);
return; return;
} }
//gitee
if (value.type === IDP_TYPE.GITEE_OAUTH) {
giteeOauthOnClick(value.code);
return;
}
//GITHUB跳转页面 //GITHUB跳转页面
if (value.type === IDP_TYPE.GITHUB_OAUTH) { if (value.type === IDP_TYPE.GITHUB_OAUTH) {
githubOauthOnClick(value.code); githubOauthOnClick(value.code);