From 2da0ddec6a51de36a2589c70d72c772c205f4ced Mon Sep 17 00:00:00 2001 From: smallbun <2689170096@qq.com> Date: Sat, 26 Aug 2023 18:11:06 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=AE=8C=E5=96=84=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=AE=9D=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../alipay/AlipayIdpOAuth2Config.java | 13 ++ .../alipay/client/AlipayClient.java | 195 ++++++++++++++++++ .../AlipaySystemOauthTokenResponse.java | 73 +++++++ .../AlipaySystemUserInfoShareResponse.java | 79 +++++++ .../AlipayAuthenticationConfigurer.java | 30 ++- .../AlipayAuthenticationConstants.java | 5 + .../AlipayLoginAuthenticationFilter.java | 109 +++++++++- .../src/components/IconFont/lib/iconfont.js | 2 +- .../components/Config/AliPayOauthConfig.tsx | 79 +++++++ .../components/Config/Config.tsx | 8 +- .../components/Config/GiteeOauthConfig.tsx | 14 +- .../components/Config/GithubOauthConfig.tsx | 8 +- .../components/CreateModal/CreateModal.tsx | 12 +- .../pages/authn/IdentityProvider/constant.ts | 13 +- .../authn/IdentityProvider/locales/zh-CN.ts | 41 +++- .../authn/IdentityProviderConverter.java | 5 +- .../security/IdpRedirectParameterMatcher.java | 6 +- .../security/PortalSecurityConfiguration.java | 18 +- .../src/components/IconFont/lib/iconfont.js | 2 +- .../main/portal-fe/src/constants/index.tsx | 1 + .../main/portal-fe/src/pages/Login/Login.tsx | 20 ++ 21 files changed, 686 insertions(+), 47 deletions(-) create mode 100644 eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipayClient.java create mode 100644 eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemOauthTokenResponse.java create mode 100644 eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemUserInfoShareResponse.java create mode 100644 eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/AliPayOauthConfig.tsx diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/AlipayIdpOAuth2Config.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/AlipayIdpOAuth2Config.java index 1ced91b8..53c9597a 100644 --- a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/AlipayIdpOAuth2Config.java +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/AlipayIdpOAuth2Config.java @@ -33,10 +33,23 @@ import jakarta.validation.constraints.NotBlank; @Data @EqualsAndHashCode(callSuper = true) public class AlipayIdpOAuth2Config extends IdentityProviderConfig { + /** * 商户ID */ @NotBlank(message = "商户ID不能为空") private String appId; + /** + * 应用私钥 + */ + @NotBlank(message = "应用私钥") + private String appPrivateKey; + + /** + * 支付宝公钥 + */ + @NotBlank(message = "支付宝公钥") + private String alipayPublicKey; + } diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipayClient.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipayClient.java new file mode 100644 index 00000000..c78c602e --- /dev/null +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipayClient.java @@ -0,0 +1,195 @@ +/* + * eiam-authentication-alipay - 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.alipay.client; + +import java.util.Map; + +import com.aliyun.tea.*; + +/** + * + * @author TopIAM + * Created by support@topiam.cn on 2023/8/25 22:26 + */ +public class AlipayClient { + + public com.alipay.easysdk.kernel.Client kernel; + + public AlipayClient(com.alipay.easysdk.kernel.Client kernel) { + this.kernel = kernel; + } + + /** + * 获取token + * + * @param code {@link String} + * @return {@link AlipaySystemOauthTokenResponse} + * @throws Exception Exception + */ + public AlipaySystemOauthTokenResponse getOauthToken(String code) throws Exception { + java.util.Map runtime = getRuntime(); + TeaRequest request = null; + long now = System.currentTimeMillis(); + int retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime.get("retry"), retryTimes, + now)) { + if (retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime.get("backoff"), retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + retryTimes = retryTimes + 1; + try { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.system.oauth.token"), + new TeaPair("app_id", kernel.getConfig("appId")), + new TeaPair("timestamp", kernel.getTimestamp()), new TeaPair("format", "json"), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", kernel.getConfig("signType")), + new TeaPair("app_cert_sn", kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", kernel.getAlipayRootCertSN())); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter.buildMap( + new TeaPair("grant_type", "authorization_code"), new TeaPair("code", code)); + request = getRequest(systemParams, bizParams, textParams); + TeaResponse response = Tea.doAction(request, runtime); + + java.util.Map respMap = kernel.readAsJson(response, + "alipay.system.oauth.token"); + if (kernel.isCertMode()) { + if (kernel.verify(respMap, + kernel.extractAlipayPublicKey(kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(kernel.toRespModel(respMap), + new AlipaySystemOauthTokenResponse()); + } + + } else { + if (kernel.verify(respMap, kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(kernel.toRespModel(respMap), + new AlipaySystemOauthTokenResponse()); + } + + } + + throw new TeaException( + TeaConverter.buildMap(new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。"))); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(request); + } + + /** + * 获取用户信息 + * + * @param authToken {@link String} + * @return {@link AlipaySystemOauthTokenResponse} + * @throws Exception Exception + */ + public AlipaySystemUserInfoShareResponse getUserInfo(String authToken) throws Exception { + java.util.Map runtime = getRuntime(); + + TeaRequest request = null; + long now = System.currentTimeMillis(); + int retryTimes = 0; + while (Tea.allowRetry((java.util.Map) runtime.get("retry"), retryTimes, + now)) { + if (retryTimes > 0) { + int backoffTime = Tea.getBackoffTime(runtime.get("backoff"), retryTimes); + if (backoffTime > 0) { + Tea.sleep(backoffTime); + } + } + retryTimes = retryTimes + 1; + try { + java.util.Map systemParams = TeaConverter.buildMap( + new TeaPair("method", "alipay.user.info.share"), + new TeaPair("app_id", kernel.getConfig("appId")), + new TeaPair("timestamp", kernel.getTimestamp()), new TeaPair("format", "json"), + new TeaPair("charset", "UTF-8"), + new TeaPair("sign_type", kernel.getConfig("signType")), + new TeaPair("app_cert_sn", kernel.getMerchantCertSN()), + new TeaPair("alipay_root_cert_sn", kernel.getAlipayRootCertSN())); + java.util.Map bizParams = new java.util.HashMap<>(); + java.util.Map textParams = TeaConverter + .buildMap(new TeaPair("auth_token", authToken)); + request = getRequest(systemParams, bizParams, textParams); + TeaResponse response = Tea.doAction(request, runtime); + + java.util.Map respMap = kernel.readAsJson(response, + "alipay.user.info.share"); + if (kernel.isCertMode()) { + if (kernel.verify(respMap, + kernel.extractAlipayPublicKey(kernel.getAlipayCertSN(respMap)))) { + return TeaModel.toModel(kernel.toRespModel(respMap), + new AlipaySystemUserInfoShareResponse()); + } + + } else { + if (kernel.verify(respMap, kernel.getConfig("alipayPublicKey"))) { + return TeaModel.toModel(kernel.toRespModel(respMap), + new AlipaySystemUserInfoShareResponse()); + } + + } + + throw new TeaException( + TeaConverter.buildMap(new TeaPair("message", "验签失败,请检查支付宝公钥设置是否正确。"))); + } catch (Exception e) { + if (Tea.isRetryable(e)) { + continue; + } + throw new RuntimeException(e); + } + } + + throw new TeaUnretryableException(request); + } + + private TeaRequest getRequest(Map systemParams, Map bizParams, + Map textParams) throws Exception { + TeaRequest request = new TeaRequest(); + + request.protocol = kernel.getConfig("protocol"); + request.method = "POST"; + request.pathname = "/gateway.do"; + request.headers = TeaConverter.buildMap( + new TeaPair("host", kernel.getConfig("gatewayHost")), + new TeaPair("content-type", "application/x-www-form-urlencoded;charset=utf-8")); + request.query = kernel.sortMap(TeaConverter.merge( + String.class, TeaConverter.buildMap(new TeaPair("sign", kernel.sign(systemParams, + bizParams, textParams, kernel.getConfig("merchantPrivateKey")))), + systemParams, textParams)); + request.body = Tea.toReadable(kernel.toUrlEncodedRequestBody(bizParams)); + return request; + } + + private java.util.Map getRuntime() throws Exception { + return TeaConverter.buildMap(new TeaPair("ignoreSSL", kernel.getConfig("ignoreSSL")), + new TeaPair("httpProxy", kernel.getConfig("httpProxy")), + new TeaPair("connectTimeout", 15000), new TeaPair("readTimeout", 15000), + new TeaPair("retry", TeaConverter.buildMap(new TeaPair("maxAttempts", 0)))); + } + +} diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemOauthTokenResponse.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemOauthTokenResponse.java new file mode 100644 index 00000000..2c92ad68 --- /dev/null +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemOauthTokenResponse.java @@ -0,0 +1,73 @@ +/* + * eiam-authentication-alipay - 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.alipay.client; + +import com.aliyun.tea.*; + +import lombok.Getter; +import lombok.Setter; + +/** + * + * @author TopIAM + * Created by support@topiam.cn on 2023/8/25 22:26 + */ +@Getter +@Setter +public class AlipaySystemOauthTokenResponse extends TeaModel { + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("open_id") + @Validation(required = true) + public String openId; + + @NameInMap("access_token") + @Validation(required = true) + public String accessToken; + + @NameInMap("expires_in") + @Validation(required = true) + public Long expiresIn; + + @NameInMap("refresh_token") + @Validation(required = true) + public String refreshToken; + + @NameInMap("re_expires_in") + @Validation(required = true) + public Long reExpiresIn; + +} diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemUserInfoShareResponse.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemUserInfoShareResponse.java new file mode 100644 index 00000000..afd83932 --- /dev/null +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/client/AlipaySystemUserInfoShareResponse.java @@ -0,0 +1,79 @@ +/* + * eiam-authentication-alipay - 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.alipay.client; + +import com.aliyun.tea.NameInMap; +import com.aliyun.tea.TeaModel; +import com.aliyun.tea.Validation; + +import lombok.Getter; +import lombok.Setter; + +/** + * + * @author TopIAM + * Created by support@topiam.cn on 2023/8/25 22:26 + */ +@Getter +@Setter +public class AlipaySystemUserInfoShareResponse extends TeaModel { + @NameInMap("http_body") + @Validation(required = true) + public String httpBody; + + @NameInMap("code") + @Validation(required = true) + public String code; + + @NameInMap("msg") + @Validation(required = true) + public String msg; + + @NameInMap("sub_code") + @Validation(required = true) + public String subCode; + + @NameInMap("sub_msg") + @Validation(required = true) + public String subMsg; + + @NameInMap("user_id") + @Validation(required = true) + public String userId; + + @NameInMap("avatar") + @Validation(required = true) + public String avatar; + + @NameInMap("city") + @Validation(required = true) + public Long city; + + @NameInMap("nick_name") + @Validation(required = true) + public String nickName; + + @NameInMap("province") + @Validation(required = true) + public Long province; + + @NameInMap("gender") + @Validation(required = true) + public Long gender; + +} diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/configurer/AlipayAuthenticationConfigurer.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/configurer/AlipayAuthenticationConfigurer.java index 61321b51..974c4086 100644 --- a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/configurer/AlipayAuthenticationConfigurer.java +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/configurer/AlipayAuthenticationConfigurer.java @@ -17,8 +17,11 @@ */ package cn.topiam.employee.authentication.alipay.configurer; +import org.springframework.http.HttpMethod; 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; @@ -29,6 +32,10 @@ import cn.topiam.employee.authentication.alipay.filter.AlipayLoginAuthentication import cn.topiam.employee.authentication.common.service.UserIdpService; import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository; +import lombok.NonNull; +import lombok.Setter; +import static cn.topiam.employee.support.security.util.HttpSecurityFilterOrderRegistrationUtils.putFilterBefore; + /** * 认证配置 * @@ -37,6 +44,9 @@ import cn.topiam.employee.common.repository.authentication.IdentityProviderRepos */ public class AlipayAuthenticationConfigurer extends AbstractAuthenticationFilterConfigurer { + @Setter + @NonNull + private String loginProcessingUrl = AlipayLoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI; private final IdentityProviderRepository identityProviderRepository; private final UserIdpService userIdpService; @@ -49,6 +59,24 @@ public class AlipayAuthenticationConfigurer extends this.userIdpService = userIdpService; } + @Override + public void init(HttpSecurity http) throws Exception { + //支付宝登录认证 + this.setAuthenticationFilter( + new AlipayLoginAuthenticationFilter(userIdpService, identityProviderRepository)); + putFilterBefore(http, this.getAuthenticationFilter(), + OAuth2LoginAuthenticationFilter.class); + + //支付宝请求重定向 + http.addFilterBefore( + new AlipayAuthorizationRequestRedirectFilter(identityProviderRepository), + OAuth2AuthorizationRequestRedirectFilter.class); + + //登录处理地址 + super.loginProcessingUrl(this.loginProcessingUrl); + super.init(http); + } + /** * Create the {@link RequestMatcher} given a loginProcessingUrl * @@ -58,7 +86,7 @@ public class AlipayAuthenticationConfigurer extends */ @Override protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) { - return new AntPathRequestMatcher(loginProcessingUrl); + return new AntPathRequestMatcher(loginProcessingUrl, HttpMethod.GET.name()); } public RequestMatcher getRequestMatcher() { diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/constant/AlipayAuthenticationConstants.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/constant/AlipayAuthenticationConstants.java index c622632f..4b1a465a 100644 --- a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/constant/AlipayAuthenticationConstants.java +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/constant/AlipayAuthenticationConstants.java @@ -30,4 +30,9 @@ public class AlipayAuthenticationConstants { public static final String USER_INFO_SCOPE = "auth_user"; public static final String APP_ID = "app_id"; + + public static final String AUTH_CODE = "auth_code"; + + public static final String SUCCESS_CODE = "200"; + } diff --git a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/filter/AlipayLoginAuthenticationFilter.java b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/filter/AlipayLoginAuthenticationFilter.java index 0bf7f3f1..1210e0e3 100644 --- a/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/filter/AlipayLoginAuthenticationFilter.java +++ b/eiam-authentication/eiam-authentication-alipay/src/main/java/cn/topiam/employee/authentication/alipay/filter/AlipayLoginAuthenticationFilter.java @@ -18,25 +18,49 @@ package cn.topiam.employee.authentication.alipay.filter; import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationServiceException; 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.JSONObject; +import com.alipay.easysdk.kernel.Client; +import com.alipay.easysdk.kernel.Config; +import com.alipay.easysdk.kernel.Context; + +import cn.topiam.employee.authentication.alipay.AlipayIdpOAuth2Config; +import cn.topiam.employee.authentication.alipay.client.AlipayClient; +import cn.topiam.employee.authentication.alipay.client.AlipaySystemOauthTokenResponse; +import cn.topiam.employee.authentication.alipay.client.AlipaySystemUserInfoShareResponse; +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.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 cn.topiam.employee.support.util.HttpUrlUtils; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import static com.taobao.api.Constants.SDK_VERSION; + +import static cn.topiam.employee.authentication.alipay.constant.AlipayAuthenticationConstants.AUTH_CODE; import static cn.topiam.employee.authentication.common.IdentityProviderType.ALIPAY_OAUTH; -import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.PROVIDER_CODE; +import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.*; +import static cn.topiam.employee.authentication.common.constant.AuthenticationConstants.INVALID_STATE_PARAMETER_ERROR_CODE; /** * 支付宝 登录过滤器 @@ -54,14 +78,12 @@ public class AlipayLoginAuthenticationFilter extends AbstractIdpAuthenticationPr /** * Creates a new instance * - * @param defaultFilterProcessesUrl the {@link String} * @param userIdpService {@link UserIdpService} * @param identityProviderRepository {@link IdentityProviderRepository} */ - protected AlipayLoginAuthenticationFilter(String defaultFilterProcessesUrl, - UserIdpService userIdpService, - IdentityProviderRepository identityProviderRepository) { - super(defaultFilterProcessesUrl, userIdpService, identityProviderRepository); + public AlipayLoginAuthenticationFilter(UserIdpService userIdpService, + IdentityProviderRepository identityProviderRepository) { + super(REQUEST_MATCHER, userIdpService, identityProviderRepository); } @Override @@ -69,11 +91,76 @@ public class AlipayLoginAuthenticationFilter extends AbstractIdpAuthenticationPr HttpServletResponse response) throws AuthenticationException, IOException, ServletException { - if (!REQUEST_MATCHER.matches(request)) { - throw new AuthenticationServiceException( - "Authentication method not supported: " + request.getMethod()); + 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 支付宝为auth_code + String code = request.getParameter(AUTH_CODE); + if (StringUtils.isEmpty(code)) { + logger.error("支付宝登录 auth_code 参数不存在,认证失败"); + OAuth2Error oauth2Error = new OAuth2Error(INVALID_CODE_PARAMETER_ERROR_CODE); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); } - return null; + // state + String state = request.getParameter(OAuth2ParameterNames.STATE); + if (StringUtils.isEmpty(state)) { + logger.error("支付宝登录 state 参数不存在,认证失败"); + OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + //验证state + if (!authorizationRequest.getState().equals(state)) { + logger.error("支付宝登录 state 匹配不一致,认证失败"); + OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + //获取身份提供商 + IdentityProviderEntity provider = getIdentityProviderEntity(providerCode); + AlipayIdpOAuth2Config idpOauthConfig = JSONObject.parseObject(provider.getConfig(), + AlipayIdpOAuth2Config.class); + if (Objects.isNull(idpOauthConfig)) { + logger.error("未查询到支付宝登录配置"); + //无效身份提供商 + OAuth2Error oauth2Error = new OAuth2Error(INVALID_IDP_CONFIG); + throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); + } + try { + AlipayClient client = new AlipayClient( + new Client(new Context(getConfig(idpOauthConfig), SDK_VERSION))); + AlipaySystemOauthTokenResponse token = client.getOauthToken(code); + if (!StringUtils.isBlank(token.getCode())) { + logger.error("支付宝认证获取 access_token 失败: [" + token.getHttpBody() + "]"); + throw new TopIamException(token.getSubMsg()); + } + String accessToken = token.getAccessToken(); + AlipaySystemUserInfoShareResponse userInfo = client.getUserInfo(accessToken); + if (!StringUtils.isBlank(userInfo.getCode())) { + logger.error("支付宝认证获取用户信息失败: [" + userInfo.getHttpBody() + "]"); + throw new TopIamException(userInfo.getSubMsg()); + } + //执行逻辑 + IdpUserDetails idpUserDetails = IdpUserDetails.builder().openId(token.getOpenId()) + .providerType(ALIPAY_OAUTH).providerCode(providerCode).providerId(providerId) + .avatarUrl(userInfo.getAvatar()).nickName(userInfo.getNickName()).build(); + return attemptAuthentication(request, response, idpUserDetails); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static Config getConfig(AlipayIdpOAuth2Config idpOauthConfig) { + Config config = new Config(); + config.protocol = "https"; + config.gatewayHost = "openapi.alipay.com"; + config.appId = idpOauthConfig.getAppId(); + config.signType = "RSA2"; + config.alipayPublicKey = idpOauthConfig.getAlipayPublicKey(); + config.merchantPrivateKey = idpOauthConfig.getAppPrivateKey(); + return config; } public static String getLoginUrl(String providerId) { diff --git a/eiam-console/src/main/console-fe/src/components/IconFont/lib/iconfont.js b/eiam-console/src/main/console-fe/src/components/IconFont/lib/iconfont.js index e6a97530..47c2c219 100644 --- a/eiam-console/src/main/console-fe/src/components/IconFont/lib/iconfont.js +++ b/eiam-console/src/main/console-fe/src/components/IconFont/lib/iconfont.js @@ -15,4 +15,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -window._iconfont_svg_string_3203993='',function(c){var l=(l=document.getElementsByTagName("script"))[l.length-1],a=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var h,t,i,p,m,d=function(l,a){a.parentNode.insertBefore(l,a)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_3203993,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(l=document.body).firstChild?d(a,l.firstChild):l.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,p=c.document,m=!1,o(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,z())})}function z(){m||(m=!0,i())}function o(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(o,50)}z()}}(window); +window._iconfont_svg_string_3203993='',function(c){var l=(l=document.getElementsByTagName("script"))[l.length-1],a=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var h,t,i,p,m,d=function(l,a){a.parentNode.insertBefore(l,a)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_3203993,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(l=document.body).firstChild?d(a,l.firstChild):l.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,p=c.document,m=!1,o(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,z())})}function z(){m||(m=!0,i())}function o(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(o,50)}z()}}(window); diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/AliPayOauthConfig.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/AliPayOauthConfig.tsx new file mode 100644 index 00000000..bcd9937e --- /dev/null +++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/AliPayOauthConfig.tsx @@ -0,0 +1,79 @@ +/* + * 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 . + */ +import { ProFormText } from '@ant-design/pro-components'; +import CallbackUrl from './CallbackUrl'; +import { useIntl } from '@umijs/max'; + +/** + * AliPay 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/Config/Config.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/Config.tsx index 97b9fbd9..e969a35a 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 @@ -26,6 +26,7 @@ import WeWorkScanCode from './WeWorkScanCodeConfig'; import GithubOauthConfig from './GithubOauthConfig'; import GiteeOauthConfig from './GiteeOauthConfig'; import { useIntl } from '@umijs/max'; +import AliPayOauthConfig from '@/pages/authn/IdentityProvider/components/Config/AliPayOauthConfig'; /** * Config @@ -43,10 +44,11 @@ const Config = (props: { type: IdentityProviderType | string; isCreate?: boolean {type === IdentityProviderType.wechatwork_qr && } {type === IdentityProviderType.dingtalk_qr && } {type === IdentityProviderType.dingtalk_oauth && } - {type === IdentityProviderType.qq && } + {type === IdentityProviderType.qq_oauth && } {type === IdentityProviderType.feishu_oauth && } - {type === IdentityProviderType.gitee && } - {type === IdentityProviderType.github && } + {type === IdentityProviderType.gitee_oauth && } + {type === IdentityProviderType.github_oauth && } + {type === IdentityProviderType.alipay_oauth && } { <> {!isCreate && } diff --git a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/GithubOauthConfig.tsx b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/GithubOauthConfig.tsx index 42dd8f5c..ea74aab4 100644 --- a/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/GithubOauthConfig.tsx +++ b/eiam-console/src/main/console-fe/src/pages/authn/IdentityProvider/components/Config/GithubOauthConfig.tsx @@ -32,7 +32,9 @@ const QqOauthConfig = (props: { isCreate: boolean }) => { <> { { }), }, { - value: IdentityProviderType.qq, + value: IdentityProviderType.qq_oauth, label: intl.formatMessage({ id: 'pages.authn.identity_provider.create_modal.form.type.qq', }), }, { - value: IdentityProviderType.github, + value: IdentityProviderType.alipay_oauth, + label: intl.formatMessage({ + id: 'pages.authn.identity_provider.create_modal.form.type.alipay_oauth', + }), + }, + { + value: IdentityProviderType.github_oauth, label: intl.formatMessage({ id: 'pages.authn.identity_provider.create_modal.form.type.github', }), }, { - value: IdentityProviderType.gitee, + value: IdentityProviderType.gitee_oauth, label: intl.formatMessage({ id: 'pages.authn.identity_provider.create_modal.form.type.gitee', }), 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 a774e8d7..451e758e 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 @@ -34,10 +34,11 @@ export enum IdentityProviderType { dingtalk_oauth = 'dingtalk_oauth', ldap = 'ldap', //社交 - qq = 'qq_oauth', - gitee = 'gitee_oauth', + qq_oauth = 'qq_oauth', + gitee_oauth = 'gitee_oauth', wechat_qr = 'wechat_qr', - github = 'github_oauth', + github_oauth = 'github_oauth', + alipay_oauth = 'alipay_oauth', } /** @@ -48,11 +49,11 @@ export const EXIST_CALLBACK = [ IdentityProviderType.dingtalk_qr, IdentityProviderType.dingtalk_oauth, IdentityProviderType.wechat_qr, - IdentityProviderType.qq, + IdentityProviderType.qq_oauth, IdentityProviderType.feishu_oauth, IdentityProviderType.feishu_oauth, - IdentityProviderType.gitee, - IdentityProviderType.github, + IdentityProviderType.gitee_oauth, + IdentityProviderType.github_oauth, ]; export const DRAWER_FORM_ITEM_LAYOUT = { 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 df76c29b..cd109ab9 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 @@ -36,10 +36,11 @@ export default { 'pages.authn.identity_provider.create_modal.form.type': '创建认证源', 'pages.authn.identity_provider.create_modal.form.type.placeholder': '请选择认证提供商', '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.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.alipay_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.feishu_oauth': '飞书认证', @@ -59,8 +60,38 @@ export default { '在飞书开放平台,开发者后台 -> 企业自建应用,创建企业自建应用', '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': '客户端ID', '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.gitee_oauth.client_secret': '客户端秘钥', + 'pages.authn.identity_provider.config.gitee_oauth.client_secret.placeholder': + '请填写ClientSecret', + 'pages.authn.identity_provider.config.gitee_oauth.client_id.extra': 'Gitee应用的Client ID', + 'pages.authn.identity_provider.config.gitee_oauth.client_secret.extra': + 'Gitee应用生成的Client secret', + 'pages.authn.identity_provider.config.github_oauth.client_id': + '客户端ID', + 'pages.authn.identity_provider.config.github_oauth.client_id.placeholder': '请填写Client ID', + 'pages.authn.identity_provider.config.github_oauth.client_secret': + '客户端秘钥', + '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', + + 'pages.authn.identity_provider.config.alipay_oauth.app_id': '应用ID', + 'pages.authn.identity_provider.config.alipay_oauth.app_id.placeholder': '请填写应用ID', + 'pages.authn.identity_provider.config.alipay_oauth.app_id.extra': 'xxxxxxxxx', + 'pages.authn.identity_provider.config.alipay_oauth.app_id.placeholder.extra': 'xxxxxxx', + 'pages.authn.identity_provider.config.alipay_oauth.app_private_key': '应用私钥', + 'pages.authn.identity_provider.config.alipay_oauth.app_private_key.placeholder': + '请填写应用私钥', + 'pages.authn.identity_provider.config.alipay_oauth.app_private_key.extra': 'xxxxxxxxxxx', + 'pages.authn.identity_provider.config.alipay_oauth.alipay_public_key': '支付宝公钥', + 'pages.authn.identity_provider.config.alipay_oauth.alipay_public_key.placeholder': + '请填写支付宝公钥', + 'pages.authn.identity_provider.config.alipay_oauth.alipay_public_key.extra': 'xxxxxxxxxxxxx', + 'pages.authn.identity_provider.config.wechat_scan_code.app_id.extra': '微信扫码登录开发申请获取的AppId', 'pages.authn.identity_provider.config.wechat_scan_code.app_id.placeholder': '请填写获取的AppId', @@ -80,8 +111,4 @@ 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 945b7fac..7c7ceb35 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 @@ -33,6 +33,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.querydsl.core.types.ExpressionUtils; import com.querydsl.core.types.Predicate; +import cn.topiam.employee.authentication.alipay.AlipayIdpOAuth2Config; import cn.topiam.employee.authentication.common.IdentityProviderCategory; import cn.topiam.employee.authentication.common.IdentityProviderType; import cn.topiam.employee.authentication.common.config.IdentityProviderConfig; @@ -249,7 +250,7 @@ public interface IdentityProviderConverter { //钉钉扫码 } else if (type.equals(DINGTALK_QR.value())) { identityProviderConfig = config.to(DingTalkIdpScanCodeConfig.class); - //钉钉Oauth + //钉钉OAuth } else if (type.equals(DINGTALK_OAUTH.value())) { identityProviderConfig = config.to(DingTalkIdpOauthConfig.class); //企业微信扫码 @@ -271,7 +272,7 @@ public interface IdentityProviderConverter { } //支付宝认证 else if (type.equals(ALIPAY_OAUTH.value())) { - identityProviderConfig = config.to(GiteeIdpOAuth2Config.class); + identityProviderConfig = config.to(AlipayIdpOAuth2Config.class); } else { throw new TopIamException("不支持此身份提供商"); } diff --git a/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/IdpRedirectParameterMatcher.java b/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/IdpRedirectParameterMatcher.java index df808200..32a4a4ca 100644 --- a/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/IdpRedirectParameterMatcher.java +++ b/eiam-portal/src/main/java/cn/topiam/employee/portal/configuration/security/IdpRedirectParameterMatcher.java @@ -17,15 +17,15 @@ */ package cn.topiam.employee.portal.configuration.security; -import cn.topiam.employee.authentication.alipay.filter.AlipayAuthorizationRequestRedirectFilter; -import cn.topiam.employee.authentication.gitee.filter.GiteeAuthorizationRequestRedirectFilter; -import cn.topiam.employee.authentication.github.filter.GithubOAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.web.util.matcher.OrRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; +import cn.topiam.employee.authentication.alipay.filter.AlipayAuthorizationRequestRedirectFilter; import cn.topiam.employee.authentication.dingtalk.filter.DingtalkOAuth2AuthorizationRequestRedirectFilter; import cn.topiam.employee.authentication.dingtalk.filter.DingtalkScanCodeAuthorizationRequestGetFilter; import cn.topiam.employee.authentication.feishu.filter.FeiShuAuthorizationRequestRedirectFilter; +import cn.topiam.employee.authentication.gitee.filter.GiteeAuthorizationRequestRedirectFilter; +import cn.topiam.employee.authentication.github.filter.GithubOAuth2AuthorizationRequestRedirectFilter; import cn.topiam.employee.authentication.qq.filter.QqOAuth2AuthorizationRequestRedirectFilter; import cn.topiam.employee.authentication.wechat.filter.WeChatScanCodeAuthorizationRequestRedirectFilter; import cn.topiam.employee.authentication.wechatwork.filter.WeChatWorkScanCodeAuthorizationRequestRedirectFilter; 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 0e851736..d8f372f9 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 @@ -51,6 +51,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import cn.topiam.employee.audit.event.AuditEventPublish; +import cn.topiam.employee.authentication.alipay.configurer.AlipayAuthenticationConfigurer; import cn.topiam.employee.authentication.common.configurer.IdpBindAuthenticationConfigurer; import cn.topiam.employee.authentication.common.jackjson.AuthenticationJacksonModule; import cn.topiam.employee.authentication.common.service.UserIdpService; @@ -59,8 +60,8 @@ import cn.topiam.employee.authentication.dingtalk.configurer.DingtalkScanCodeAut 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.otp.mail.MailOtpAuthenticationConfigurer; -import cn.topiam.employee.authentication.otp.sms.SmsOtpAuthenticationConfigurer; +import cn.topiam.employee.authentication.otp.mail.configurer.MailOtpAuthenticationConfigurer; +import cn.topiam.employee.authentication.otp.sms.configurer.SmsOtpAuthenticationConfigurer; import cn.topiam.employee.authentication.qq.configurer.QqOauthAuthenticationConfigurer; import cn.topiam.employee.authentication.wechat.configurer.WeChatScanCodeAuthenticationConfigurer; import cn.topiam.employee.authentication.wechatwork.configurer.WeChatWorkScanCodeAuthenticationConfigurer; @@ -90,14 +91,15 @@ import cn.topiam.employee.support.security.savedredirect.LoginRedirectParameterF import static org.springframework.http.HttpMethod.*; import static org.springframework.security.config.Customizer.withDefaults; +import static cn.topiam.employee.authentication.alipay.configurer.AlipayAuthenticationConfigurer.alipayOauth; import static cn.topiam.employee.authentication.common.configurer.IdpBindAuthenticationConfigurer.idpBind; 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.gitee.configurer.GiteeAuthenticationConfigurer.giteeOauth; 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.otp.mail.configurer.MailOtpAuthenticationConfigurer.mailOtp; +import static cn.topiam.employee.authentication.otp.sms.configurer.SmsOtpAuthenticationConfigurer.smsOtp; import static cn.topiam.employee.authentication.qq.configurer.QqOauthAuthenticationConfigurer.qq; import static cn.topiam.employee.authentication.wechat.configurer.WeChatScanCodeAuthenticationConfigurer.weChatScanCode; import static cn.topiam.employee.authentication.wechatwork.configurer.WeChatWorkScanCodeAuthenticationConfigurer.weChatWorkScanCode; @@ -217,7 +219,13 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration requestMatchers.add(giteeCode.getRequestMatcher()); httpSecurity.apply(giteeCode); - //支付宝 todo + //支付宝 + AlipayAuthenticationConfigurer alipayOauth = alipayOauth(identityProviderRepository, userIdpService) + .successHandler(successHandler) + .failureHandler(failureHandler) + .authenticationDetailsSource(authenticationDetailsSource); + requestMatchers.add(alipayOauth.getRequestMatcher()); + httpSecurity.apply(alipayOauth); //RequestMatcher OrRequestMatcher requestMatcher = new OrRequestMatcher(requestMatchers); diff --git a/eiam-portal/src/main/portal-fe/src/components/IconFont/lib/iconfont.js b/eiam-portal/src/main/portal-fe/src/components/IconFont/lib/iconfont.js index b724cad7..ba64b0ec 100644 --- a/eiam-portal/src/main/portal-fe/src/components/IconFont/lib/iconfont.js +++ b/eiam-portal/src/main/portal-fe/src/components/IconFont/lib/iconfont.js @@ -15,4 +15,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -window._iconfont_svg_string_3203993='',function(c){var l=(l=document.getElementsByTagName("script"))[l.length-1],a=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var h,t,i,p,m,d=function(l,a){a.parentNode.insertBefore(l,a)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_3203993,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(l=document.body).firstChild?d(a,l.firstChild):l.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,p=c.document,m=!1,o(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,z())})}function z(){m||(m=!0,i())}function o(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(o,50)}z()}}(window); +window._iconfont_svg_string_3203993='',function(c){var l=(l=document.getElementsByTagName("script"))[l.length-1],a=l.getAttribute("data-injectcss"),l=l.getAttribute("data-disable-injectsvg");if(!l){var h,t,i,p,m,d=function(l,a){a.parentNode.insertBefore(l,a)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}h=function(){var l,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_3203993,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(l=document.body).firstChild?d(a,l.firstChild):l.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),h()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=h,p=c.document,m=!1,o(),p.onreadystatechange=function(){"complete"==p.readyState&&(p.onreadystatechange=null,z())})}function z(){m||(m=!0,i())}function o(){try{p.documentElement.doScroll("left")}catch(l){return void setTimeout(o,50)}z()}}(window); diff --git a/eiam-portal/src/main/portal-fe/src/constants/index.tsx b/eiam-portal/src/main/portal-fe/src/constants/index.tsx index add472e4..b0fdaab0 100644 --- a/eiam-portal/src/main/portal-fe/src/constants/index.tsx +++ b/eiam-portal/src/main/portal-fe/src/constants/index.tsx @@ -37,6 +37,7 @@ export enum IDP_TYPE { QQ_OAUTH = 'qq_oauth', GITEE_OAUTH = 'gitee_oauth', GITHUB_OAUTH = 'github_oauth', + ALIPAY_OAUTH = 'alipay_oauth', WEIBO_OAUTH = 'weibo_oauth', WECHATWORK_QR = 'wechatwork_qr', } 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 252c5435..b69eafb2 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 @@ -214,6 +214,21 @@ const Login = () => { window.open(path, '_self'); }; + /** + * alipay + * + * @param id + */ + const alipayOauthOnClick = (id: string) => { + const query = queryString.parse(history.location.search); + const { redirect_uri } = query as { redirect_uri: string }; + let path = `/api/v1/authorization/alipay_oauth/${id}`; + if (redirect_uri) { + path = `${path}?redirect_uri=${redirect_uri}`; + } + window.open(path, '_self'); + }; + /** * 提交 * @@ -518,6 +533,11 @@ const Login = () => { githubOauthOnClick(value.code); return; } + //支付宝,跳转页面 + if (value.type === IDP_TYPE.ALIPAY_OAUTH) { + alipayOauthOnClick(value.code); + return; + } //其他方式,跳转页面 else { setCurrentProvider({