fix: normalize channel login open ids
This commit is contained in:
parent
2a7be2ca92
commit
916ce628be
@ -224,9 +224,18 @@ public class EndpointRestController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/account/login/channel")
|
@PostMapping("/account/login/channel")
|
||||||
public TokenCredentialCO login(@RequestBody @Validated UserChannelCredentialCmd cmd, HttpServletRequest request) {
|
public TokenCredentialCO login(@RequestBody @Validated UserChannelCredentialCmd cmd, HttpServletRequest request) {
|
||||||
TokenCredentialCO tokenCredentialCO = processToken.createUserCredential(ResponseAssert.requiredSuccess(
|
try {
|
||||||
appUserAccountClient.channelCredential(cmd)));
|
TokenCredentialCO tokenCredentialCO = processToken.createUserCredential(ResponseAssert.requiredSuccess(
|
||||||
return submitLoginAccessValidation(tokenCredentialCO, cmd.requireReqSysOrigin(), cmd.getReqZoneId(), request);
|
appUserAccountClient.channelCredential(cmd)));
|
||||||
|
return submitLoginAccessValidation(tokenCredentialCO, cmd.requireReqSysOrigin(), cmd.getReqZoneId(), request);
|
||||||
|
} catch (ResponseException ex) {
|
||||||
|
if (isChannelCredentialDecodeError(ex)) {
|
||||||
|
log.warn("channel login credential decode error, return USER_NOT_REGISTERED. authType={}",
|
||||||
|
cmd.getAuthType());
|
||||||
|
throw new ResponseException(UserErrorCode.USER_NOT_REGISTERED);
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -287,6 +296,13 @@ public class EndpointRestController {
|
|||||||
|| Objects.equals(ex.getErrorCode(), UserErrorCode.SOURCE_REGISTERED.getCode());
|
|| Objects.equals(ex.getErrorCode(), UserErrorCode.SOURCE_REGISTERED.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isChannelCredentialDecodeError(ResponseException ex) {
|
||||||
|
return Objects.equals(ex.getErrorCode(), ResponseErrorCode.NOT_ACCEPTABLE.getCode())
|
||||||
|
&& Objects.equals(ex.getErrorCodeName(), "ERROR_INNER_DECODER")
|
||||||
|
&& Objects.toString(ex.getExtValues(), "")
|
||||||
|
.contains("/app-user/account/channel/credential");
|
||||||
|
}
|
||||||
|
|
||||||
private TokenCredentialCO createTokenCredential(
|
private TokenCredentialCO createTokenCredential(
|
||||||
UserAccountDTO account,
|
UserAccountDTO account,
|
||||||
String reqSysOrigin,
|
String reqSysOrigin,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import com.red.circle.tool.core.text.StringUtils;
|
|||||||
import feign.Request;
|
import feign.Request;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import feign.codec.ErrorDecoder;
|
import feign.codec.ErrorDecoder;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -69,11 +70,14 @@ public class FeignErrorDecoder implements ErrorDecoder {
|
|||||||
String errorCodeName = Objects.equals(response.status(), 429)
|
String errorCodeName = Objects.equals(response.status(), 429)
|
||||||
? "REQ_LIMIT_INNER_DECODER"
|
? "REQ_LIMIT_INNER_DECODER"
|
||||||
: "ERROR_INNER_DECODER";
|
: "ERROR_INNER_DECODER";
|
||||||
return new ResponseException(response.status(), errorCodeName, getErrorMsg(methodKey, response));
|
Map<String, Object> extValues = new HashMap<>();
|
||||||
|
extValues.put("innerRequest", reqMapping(response));
|
||||||
|
extValues.put("innerMethodKey", methodKey);
|
||||||
|
return new ResponseException(response.status(), errorCodeName, getErrorMsg(response), extValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getErrorMsg(String methodKey, Response response) {
|
private String getErrorMsg(Response response) {
|
||||||
return StringUtils.isBlankOrElse(response.reason(), "") + reqMapping(response);
|
return StringUtils.isBlankOrElse(response.reason(), "Inner service error");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResponseException parseResponseException(String methodKey, Response response) {
|
private ResponseException parseResponseException(String methodKey, Response response) {
|
||||||
@ -103,15 +107,44 @@ public class FeignErrorDecoder implements ErrorDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream inputStream = response.body().asInputStream()) {
|
try (InputStream inputStream = response.body().asInputStream()) {
|
||||||
String responseCompression = ApplicationContextUtils.getApplicationContext()
|
byte[] bodyBytes = inputStream.readAllBytes();
|
||||||
.getEnvironment()
|
if (bodyBytes.length == 0) {
|
||||||
.getProperty("spring.cloud.openfeign.compression.response.enabled");
|
log.warn("Feign error response body is empty, status={}, reason={}, request={}",
|
||||||
return JacksonUtils.readValue(inputStream, new TypeReference<>() {
|
response.status(), response.reason(), reqMapping(response));
|
||||||
}, Objects.equals(responseCompression, "true"));
|
return null;
|
||||||
|
}
|
||||||
|
boolean gzipEncoded = isGzipEncoded(response);
|
||||||
|
ResultResponse<Void> responseBody = parseResponseBytes(response, bodyBytes, gzipEncoded);
|
||||||
|
if (Objects.nonNull(responseBody)) {
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
return parseResponseBytes(response, bodyBytes, !gzipEncoded);
|
||||||
} catch (IOException | RuntimeException ex) {
|
} catch (IOException | RuntimeException ex) {
|
||||||
log.warn("Parse feign error response body failed, status={}, reason={}, request={}",
|
log.warn("Read feign error response body failed, status={}, reason={}, request={}",
|
||||||
response.status(), response.reason(), reqMapping(response), ex);
|
response.status(), response.reason(), reqMapping(response), ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResultResponse<Void> parseResponseBytes(
|
||||||
|
Response response,
|
||||||
|
byte[] bodyBytes,
|
||||||
|
boolean compression) {
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bodyBytes)) {
|
||||||
|
return JacksonUtils.readValue(inputStream, new TypeReference<>() {
|
||||||
|
}, compression);
|
||||||
|
} catch (IOException | RuntimeException ex) {
|
||||||
|
log.warn("Parse feign error response body failed, status={}, reason={}, request={}, compression={}",
|
||||||
|
response.status(), response.reason(), reqMapping(response), compression, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGzipEncoded(Response response) {
|
||||||
|
return response.headers().entrySet().stream()
|
||||||
|
.filter(entry -> Objects.nonNull(entry.getKey()))
|
||||||
|
.filter(entry -> "Content-Encoding".equalsIgnoreCase(entry.getKey()))
|
||||||
|
.flatMap(entry -> entry.getValue().stream())
|
||||||
|
.anyMatch(value -> "gzip".equalsIgnoreCase(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.red.circle.other.inner.model.cmd.user;
|
|||||||
|
|
||||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||||
import com.red.circle.other.inner.enums.user.AuthTypeEnum;
|
import com.red.circle.other.inner.enums.user.AuthTypeEnum;
|
||||||
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -33,10 +34,14 @@ public class UserChannelCredentialCmd extends AppExtCommand {
|
|||||||
private String openId;
|
private String openId;
|
||||||
|
|
||||||
public String openId() {
|
public String openId() {
|
||||||
if (openId.contains("_") && !AuthTypeEnum.HUAWEI.name().equals(authType.name())) {
|
if (StringUtils.isBlank(openId)) {
|
||||||
return openId;
|
return openId;
|
||||||
}
|
}
|
||||||
return this.getOpenId().concat("_").concat(this.requireReqSysOrigin());
|
String suffix = "_".concat(requireReqSysOrigin());
|
||||||
|
if (openId.endsWith(suffix)) {
|
||||||
|
return openId;
|
||||||
|
}
|
||||||
|
return openId.concat(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,11 +105,19 @@ public class CreateAccountCmd extends AppExtCommand {
|
|||||||
StringUtils.isNotBlank(this.openId)
|
StringUtils.isNotBlank(this.openId)
|
||||||
&& !Objects.equals(this.openId, "null"));
|
&& !Objects.equals(this.openId, "null"));
|
||||||
}
|
}
|
||||||
setOpenId(this.openId.concat("_").concat(requireReqSysOrigin()));
|
setOpenId(openIdWithReqSysOrigin(this.openId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String registerOpenId() {
|
public String registerOpenId() {
|
||||||
return checkTypeMobile() ? this.mobile.getFullPhoneNumber() : this.openId;
|
return checkTypeMobile() ? this.mobile.getFullPhoneNumber() : this.openId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String openIdWithReqSysOrigin(String sourceOpenId) {
|
||||||
|
String suffix = "_".concat(requireReqSysOrigin());
|
||||||
|
if (sourceOpenId.endsWith(suffix)) {
|
||||||
|
return sourceOpenId;
|
||||||
|
}
|
||||||
|
return sourceOpenId.concat(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.red.circle.other.inner.model.cmd.user;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import com.red.circle.framework.core.dto.ReqSysOrigin;
|
||||||
|
import com.red.circle.other.inner.enums.user.AuthTypeEnum;
|
||||||
|
import com.red.circle.other.inner.model.cmd.user.account.CreateAccountCmd;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UserOpenIdNormalizeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void channelLoginAppendsOriginWhenGoogleOpenIdContainsUnderscore() {
|
||||||
|
UserChannelCredentialCmd cmd = new UserChannelCredentialCmd();
|
||||||
|
cmd.setAuthType(AuthTypeEnum.GOOGLE);
|
||||||
|
cmd.setOpenId("google_open_id");
|
||||||
|
cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI"));
|
||||||
|
|
||||||
|
assertEquals("google_open_id_LIKEI", cmd.openId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void channelLoginDoesNotAppendOriginTwice() {
|
||||||
|
UserChannelCredentialCmd cmd = new UserChannelCredentialCmd();
|
||||||
|
cmd.setAuthType(AuthTypeEnum.GOOGLE);
|
||||||
|
cmd.setOpenId("google_open_id_LIKEI");
|
||||||
|
cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI"));
|
||||||
|
|
||||||
|
assertEquals("google_open_id_LIKEI", cmd.openId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void accountCreateDoesNotAppendOriginTwice() {
|
||||||
|
CreateAccountCmd cmd = new CreateAccountCmd();
|
||||||
|
cmd.setType(AuthTypeEnum.GOOGLE.name());
|
||||||
|
cmd.setOpenId("google_open_id_LIKEI");
|
||||||
|
cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI"));
|
||||||
|
cmd.changeOpenId();
|
||||||
|
|
||||||
|
assertEquals("google_open_id_LIKEI", cmd.getOpenId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -48,7 +48,15 @@ public class BindUserAuthTypeCmd extends AppExtCommand {
|
|||||||
|
|
||||||
return isTypeMobile()
|
return isTypeMobile()
|
||||||
? mobile.getFullPhoneNumber()
|
? mobile.getFullPhoneNumber()
|
||||||
: openId.concat("_").concat(requireReqSysOrigin());
|
: openIdWithReqSysOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String openIdWithReqSysOrigin() {
|
||||||
|
String suffix = "_".concat(requireReqSysOrigin());
|
||||||
|
if (openId.endsWith(suffix)) {
|
||||||
|
return openId;
|
||||||
|
}
|
||||||
|
return openId.concat(suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import com.red.circle.tool.core.text.StringUtils;
|
|||||||
import feign.Request;
|
import feign.Request;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
import feign.codec.ErrorDecoder;
|
import feign.codec.ErrorDecoder;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -69,11 +70,14 @@ public class FeignErrorDecoder implements ErrorDecoder {
|
|||||||
String errorCodeName = Objects.equals(response.status(), 429)
|
String errorCodeName = Objects.equals(response.status(), 429)
|
||||||
? "REQ_LIMIT_INNER_DECODER"
|
? "REQ_LIMIT_INNER_DECODER"
|
||||||
: "ERROR_INNER_DECODER";
|
: "ERROR_INNER_DECODER";
|
||||||
return new ResponseException(response.status(), errorCodeName, getErrorMsg(methodKey, response));
|
Map<String, Object> extValues = new HashMap<>();
|
||||||
|
extValues.put("innerRequest", reqMapping(response));
|
||||||
|
extValues.put("innerMethodKey", methodKey);
|
||||||
|
return new ResponseException(response.status(), errorCodeName, getErrorMsg(response), extValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getErrorMsg(String methodKey, Response response) {
|
private String getErrorMsg(Response response) {
|
||||||
return StringUtils.isBlankOrElse(response.reason(), "") + reqMapping(response);
|
return StringUtils.isBlankOrElse(response.reason(), "Inner service error");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResponseException parseResponseException(String methodKey, Response response) {
|
private ResponseException parseResponseException(String methodKey, Response response) {
|
||||||
@ -103,15 +107,44 @@ public class FeignErrorDecoder implements ErrorDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream inputStream = response.body().asInputStream()) {
|
try (InputStream inputStream = response.body().asInputStream()) {
|
||||||
String responseCompression = ApplicationContextUtils.getApplicationContext()
|
byte[] bodyBytes = inputStream.readAllBytes();
|
||||||
.getEnvironment()
|
if (bodyBytes.length == 0) {
|
||||||
.getProperty("spring.cloud.openfeign.compression.response.enabled");
|
log.warn("Feign error response body is empty, status={}, reason={}, request={}",
|
||||||
return JacksonUtils.readValue(inputStream, new TypeReference<>() {
|
response.status(), response.reason(), reqMapping(response));
|
||||||
}, Objects.equals(responseCompression, "true"));
|
return null;
|
||||||
|
}
|
||||||
|
boolean gzipEncoded = isGzipEncoded(response);
|
||||||
|
ResultResponse<Void> responseBody = parseResponseBytes(response, bodyBytes, gzipEncoded);
|
||||||
|
if (Objects.nonNull(responseBody)) {
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
return parseResponseBytes(response, bodyBytes, !gzipEncoded);
|
||||||
} catch (IOException | RuntimeException ex) {
|
} catch (IOException | RuntimeException ex) {
|
||||||
log.warn("Parse feign error response body failed, status={}, reason={}, request={}",
|
log.warn("Read feign error response body failed, status={}, reason={}, request={}",
|
||||||
response.status(), response.reason(), reqMapping(response), ex);
|
response.status(), response.reason(), reqMapping(response), ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResultResponse<Void> parseResponseBytes(
|
||||||
|
Response response,
|
||||||
|
byte[] bodyBytes,
|
||||||
|
boolean compression) {
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bodyBytes)) {
|
||||||
|
return JacksonUtils.readValue(inputStream, new TypeReference<>() {
|
||||||
|
}, compression);
|
||||||
|
} catch (IOException | RuntimeException ex) {
|
||||||
|
log.warn("Parse feign error response body failed, status={}, reason={}, request={}, compression={}",
|
||||||
|
response.status(), response.reason(), reqMapping(response), compression, ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGzipEncoded(Response response) {
|
||||||
|
return response.headers().entrySet().stream()
|
||||||
|
.filter(entry -> Objects.nonNull(entry.getKey()))
|
||||||
|
.filter(entry -> "Content-Encoding".equalsIgnoreCase(entry.getKey()))
|
||||||
|
.flatMap(entry -> entry.getValue().stream())
|
||||||
|
.anyMatch(value -> "gzip".equalsIgnoreCase(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user