support wework oauth login (#267)

* feat: jooq generate oauth_app_property

* feat: jooq generate -> remove oauth_app unused columns

* feat: support wework oauth login

* feat: update oauth property validator
This commit is contained in:
vran
2022-12-24 13:00:52 +08:00
committed by GitHub
parent 396fa2f6ae
commit e340f87d7a
111 changed files with 1428 additions and 484 deletions

View File

@@ -1,26 +1,33 @@
package com.databasir.core.domain.app;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.app.converter.OauthAppConverter;
import com.databasir.core.domain.app.converter.OAuthAppResponseConverter;
import com.databasir.core.domain.app.converter.OauthAppConverter;
import com.databasir.core.domain.app.data.*;
import com.databasir.core.domain.app.handler.OAuthProcessResult;
import com.databasir.core.domain.app.handler.OpenAuthHandlers;
import com.databasir.core.domain.app.validator.OauthPropertiesValidator;
import com.databasir.core.domain.user.data.UserCreateRequest;
import com.databasir.core.domain.user.data.UserDetailResponse;
import com.databasir.core.domain.user.service.UserService;
import com.databasir.dao.impl.OauthAppDao;
import com.databasir.dao.impl.OauthAppPropertyDao;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -31,12 +38,20 @@ public class OpenAuthAppService {
private final OauthAppDao oauthAppDao;
private final OauthAppPropertyDao oauthAppPropertyDao;
private final UserService userService;
private final OAuthAppResponseConverter oauthAppResponseConverter;
private final OauthAppConverter oauthAppConverter;
private final ObjectMapper objectMapper;
private final OauthPropertiesValidator oauthPropertiesValidator;
private List<OAuthAppPlatformResponse> platforms = new ArrayList<>();
public UserDetailResponse oauthCallback(String registrationId, Map<String, String[]> params) {
// process by handler
OAuthProcessResult result = openAuthHandlers.process(registrationId, params);
@@ -63,25 +78,37 @@ public class OpenAuthAppService {
.collect(Collectors.toList());
}
@Transactional
public void deleteById(Integer id) {
if (oauthAppDao.existsById(id)) {
oauthAppDao.deleteById(id);
oauthAppPropertyDao.deleteByOauthAppId(id);
}
}
@Transactional
public void updateById(OAuthAppUpdateRequest request) {
oauthPropertiesValidator.validate(request, listPlatforms());
OauthApp pojo = oauthAppConverter.of(request);
try {
oauthAppDao.updateById(pojo);
oauthAppPropertyDao.deleteByOauthAppId(pojo.getId());
List<OauthAppProperty> properties = oauthAppConverter.toProperty(pojo.getId(), request.getProperties());
oauthAppPropertyDao.batchInsert(properties);
} catch (DuplicateKeyException e) {
throw DomainErrors.REGISTRATION_ID_DUPLICATE.exception();
}
}
@Transactional
public Integer create(OAuthAppCreateRequest request) {
oauthPropertiesValidator.validate(request, listPlatforms());
OauthApp pojo = oauthAppConverter.of(request);
try {
return oauthAppDao.insertAndReturnId(pojo);
Integer oauthAppId = oauthAppDao.insertAndReturnId(pojo);
List<OauthAppProperty> properties = oauthAppConverter.toProperty(oauthAppId, request.getProperties());
oauthAppPropertyDao.batchInsert(properties);
return oauthAppId;
} catch (DuplicateKeyException e) {
throw DomainErrors.REGISTRATION_ID_DUPLICATE.exception();
}
@@ -92,6 +119,25 @@ public class OpenAuthAppService {
}
public Optional<OAuthAppDetailResponse> getOne(Integer id) {
return oauthAppDao.selectOptionalById(id).map(oauthAppConverter::toDetailResponse);
return oauthAppDao.selectOptionalById(id).map(oauthApp -> {
List<OauthAppProperty> properties = oauthAppPropertyDao.selectByOauthAppId(id);
return oauthAppConverter.toDetailResponse(oauthApp, properties);
});
}
public List<OAuthAppPlatformResponse> listPlatforms() {
if (platforms == null || platforms.isEmpty()) {
String schemaPath = "classpath:/oauth/platform-properties-schema.json";
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(schemaPath);
try (InputStream inputStream = resource.getInputStream()) {
return objectMapper.readValue(inputStream, new TypeReference<List<OAuthAppPlatformResponse>>() {
});
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
return platforms;
}
}
}

View File

@@ -0,0 +1,31 @@
package com.databasir.core.domain.app.common;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import java.util.List;
public interface CommonProperties {
String AUTH_HOST = "auth_host";
String RESOURCE_HOST = "resource_host";
CommonProperties INSTANCE = new CommonProperties() {
};
default String get(List<OauthAppProperty> properties, String key) {
return properties.stream()
.filter(p -> p.getName().equals(key))
.map(OauthAppProperty::getValue)
.findFirst()
.orElseThrow();
}
default String getAuthHost(List<OauthAppProperty> properties) {
return get(properties, AUTH_HOST);
}
default String getResourceHost(List<OauthAppProperty> properties) {
return get(properties, RESOURCE_HOST);
}
}

View File

@@ -0,0 +1,8 @@
package com.databasir.core.domain.app.common;
public interface GithubProperties extends CommonProperties {
String CLIENT_ID = "client_id";
String CLIENT_SECRET = "client_secret";
}

View File

@@ -0,0 +1,9 @@
package com.databasir.core.domain.app.common;
public interface GitlabProperties extends CommonProperties {
String CLIENT_ID = "client_id";
String CLIENT_SECRET = "client_secret";
}

View File

@@ -0,0 +1,12 @@
package com.databasir.core.domain.app.common;
public interface WeWorkProperties extends CommonProperties {
String APP_ID = "appid";
String AGENT_ID = "agentid";
String SECRET = "secret";
String REDIRECT_URL = "redirect_uri";
}

View File

@@ -1,13 +1,15 @@
package com.databasir.core.domain.app.converter;
import com.databasir.core.domain.app.data.OAuthAppCreateRequest;
import com.databasir.core.domain.app.data.OAuthAppDetailResponse;
import com.databasir.core.domain.app.data.OAuthAppPageResponse;
import com.databasir.core.domain.app.data.OAuthAppUpdateRequest;
import com.databasir.core.domain.app.data.*;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Mapper(componentModel = "spring")
public interface OauthAppConverter {
@@ -22,5 +24,17 @@ public interface OauthAppConverter {
OAuthAppPageResponse toPageResponse(OauthApp pojo);
OAuthAppDetailResponse toDetailResponse(OauthApp pojo);
OAuthAppDetailResponse toDetailResponse(OauthApp pojo, List<OauthAppProperty> properties);
@Mapping(target = "createAt", ignore = true)
@Mapping(target = "id", ignore = true)
OauthAppProperty toProperty(Integer oauthAppId, OauthAppPropertyData property);
default List<OauthAppProperty> toProperty(Integer oauthAppId, List<OauthAppPropertyData> properties) {
if (properties == null) {
return Collections.emptyList();
}
return properties.stream().map(prop -> toProperty(oauthAppId, prop)).collect(Collectors.toList());
}
}

View File

@@ -5,6 +5,8 @@ import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
@Data
public class OAuthAppCreateRequest {
@@ -20,17 +22,6 @@ public class OAuthAppCreateRequest {
private String appIcon;
@NotBlank
private String authUrl;
private List<OauthAppPropertyData> properties = new ArrayList<>();
@NotBlank
private String resourceUrl;
@NotBlank
private String clientId;
@NotBlank
private String clientSecret;
private String scope;
}

View File

@@ -4,6 +4,8 @@ import com.databasir.dao.enums.OAuthAppType;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
public class OAuthAppDetailResponse {
@@ -18,13 +20,7 @@ public class OAuthAppDetailResponse {
private String registrationId;
private String clientId;
private String clientSecret;
private String authUrl;
private String resourceUrl;
private List<OauthAppPropertyData> properties = new ArrayList<>();
private LocalDateTime updateAt;

View File

@@ -18,12 +18,6 @@ public class OAuthAppPageResponse {
private String registrationId;
private String clientId;
private String authUrl;
private String resourceUrl;
private LocalDateTime updateAt;
private LocalDateTime createAt;

View File

@@ -0,0 +1,42 @@
package com.databasir.core.domain.app.data;
import com.databasir.dao.enums.OAuthAppType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class OAuthAppPlatformResponse {
private OAuthAppType authAppType;
private String authAppName;
@Builder.Default
private List<OAuthAppPlatformProperty> properties = new ArrayList<>();
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class OAuthAppPlatformProperty {
private String name;
private String label;
private String description;
private Boolean required;
private String defaultValue;
}
}

View File

@@ -5,6 +5,8 @@ import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
@Data
public class OAuthAppUpdateRequest {
@@ -23,18 +25,6 @@ public class OAuthAppUpdateRequest {
private String appIcon;
@NotBlank
private String authUrl;
@NotBlank
private String resourceUrl;
@NotBlank
private String clientId;
@NotBlank
private String clientSecret;
private String scope;
private List<OauthAppPropertyData> properties = new ArrayList<>();
}

View File

@@ -0,0 +1,18 @@
package com.databasir.core.domain.app.data;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class OauthAppPropertyData {
private String name;
private String value;
}

View File

@@ -1,10 +1,13 @@
package com.databasir.core.domain.app.handler;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.app.common.CommonProperties;
import com.databasir.core.domain.app.common.GithubProperties;
import com.databasir.core.domain.app.exception.DatabasirAuthenticationException;
import com.databasir.core.infrastructure.remote.github.GithubRemoteService;
import com.databasir.dao.enums.OAuthAppType;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.jooq.tools.StringUtils;
@@ -12,6 +15,7 @@ import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
import java.util.Map;
@Component
@@ -26,13 +30,16 @@ public class GithubOpenAuthHandler implements OpenAuthHandler {
}
@Override
public String authorizationUrl(OauthApp app, Map<String, String[]> requestParams) {
String authUrl = app.getAuthUrl();
String clientId = app.getClientId();
public String authorizationUrl(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams) {
String authUrl = CommonProperties.INSTANCE.getAuthHost(properties);
String clientId = CommonProperties.INSTANCE.get(properties, GithubProperties.CLIENT_ID);
String authorizeUrl = authUrl + "/login/oauth/authorize";
String url = UriComponentsBuilder.fromUriString(authorizeUrl)
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(authorizeUrl)
.queryParam("client_id", clientId)
.queryParam("scope", "read:user user:email")
.queryParam("scope", "read:user user:email");
String url = builder
.encode()
.build()
.toUriString();
@@ -40,10 +47,12 @@ public class GithubOpenAuthHandler implements OpenAuthHandler {
}
@Override
public OAuthProcessResult process(OauthApp app, Map<String, String[]> requestParams) {
String clientId = app.getClientId();
String clientSecret = app.getClientSecret();
String authUrl = app.getAuthUrl();
public OAuthProcessResult process(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams) {
String authUrl = CommonProperties.INSTANCE.getAuthHost(properties);
String clientId = CommonProperties.INSTANCE.get(properties, GithubProperties.CLIENT_ID);
String clientSecret = CommonProperties.INSTANCE.get(properties, GithubProperties.CLIENT_SECRET);
String code = requestParams.get("code")[0];
JsonNode tokenNode = githubRemoteService.getToken(authUrl, clientId, clientSecret, code)
@@ -55,7 +64,8 @@ public class GithubOpenAuthHandler implements OpenAuthHandler {
if (StringUtils.isBlank(accessToken)) {
throw new CredentialsExpiredException("授权失效,请重新登陆");
}
String resourceUrl = app.getResourceUrl();
String resourceUrl = CommonProperties.INSTANCE.get(properties, GithubProperties.RESOURCE_HOST);
String email = null;
for (JsonNode node : githubRemoteService.getEmail(resourceUrl, accessToken)) {
if (node.get("primary").asBoolean()) {

View File

@@ -1,15 +1,19 @@
package com.databasir.core.domain.app.handler;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.app.common.CommonProperties;
import com.databasir.core.domain.app.common.GitlabProperties;
import com.databasir.core.domain.app.exception.DatabasirAuthenticationException;
import com.databasir.core.infrastructure.remote.gitlab.GitlabRemoteService;
import com.databasir.dao.enums.OAuthAppType;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
import java.util.Map;
@Component
@@ -24,42 +28,52 @@ public class GitlabOpenAuthHandler implements OpenAuthHandler {
}
@Override
public String authorizationUrl(OauthApp app, Map<String, String[]> params) {
public String authorizationUrl(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> params) {
if (!params.containsKey("redirect_uri")) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception("缺少参数 redirect_uri", null);
}
String authUrl = app.getAuthUrl();
String clientId = app.getClientId();
String authUrl = CommonProperties.INSTANCE.getAuthHost(properties);
String clientId = CommonProperties.INSTANCE.get(properties, GitlabProperties.CLIENT_ID);
String authorizeUrl = authUrl + "/oauth/authorize";
String redirectUri = params.get("redirect_uri")[0];
String url = UriComponentsBuilder.fromUriString(authorizeUrl)
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(authorizeUrl)
.queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri)
.queryParam("response_type", "code")
.queryParam("state", redirectUri)
.queryParam("scope", "read_user")
.queryParam("response_type", "code")
.queryParam("scope", "read_user");
return builder
.encode()
.build()
.toUriString();
return url;
}
@Override
public OAuthProcessResult process(OauthApp app, Map<String, String[]> requestParams) {
public OAuthProcessResult process(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams) {
if (!requestParams.containsKey("redirect_uri")) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception("缺少参数 redirect_uri", null);
}
String url = app.getAuthUrl();
String url = CommonProperties.INSTANCE.getAuthHost(properties);
String code = requestParams.get("code")[0];
String state = requestParams.get("state")[0];
String redirectUri = requestParams.get("redirect_uri")[0];
String clientId = CommonProperties.INSTANCE.get(properties, GitlabProperties.CLIENT_ID);
String secret = CommonProperties.INSTANCE.get(properties, GitlabProperties.CLIENT_SECRET);
JsonNode accessTokenData =
gitlabRemoteService.getAccessToken(url, code, app.getClientId(), app.getClientSecret(), redirectUri);
gitlabRemoteService.getAccessToken(url, code, clientId, secret, redirectUri);
if (accessTokenData == null) {
throw new DatabasirAuthenticationException(DomainErrors.NETWORK_ERROR.exception());
}
String accessToken = accessTokenData.get("access_token").asText();
JsonNode userData = gitlabRemoteService.getUser(app.getResourceUrl(), accessToken);
String resourceUrl = CommonProperties.INSTANCE.getResourceHost(properties);
JsonNode userData = gitlabRemoteService.getUser(resourceUrl, accessToken);
if (userData == null) {
throw new DatabasirAuthenticationException(DomainErrors.NETWORK_ERROR.exception());
}

View File

@@ -2,14 +2,20 @@ package com.databasir.core.domain.app.handler;
import com.databasir.dao.enums.OAuthAppType;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import java.util.List;
import java.util.Map;
public interface OpenAuthHandler {
boolean support(OAuthAppType oauthAppType);
String authorizationUrl(OauthApp app, Map<String, String[]> requestParams);
String authorizationUrl(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams);
OAuthProcessResult process(OauthApp app, Map<String, String[]> requestParams);
OAuthProcessResult process(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams);
}

View File

@@ -2,7 +2,9 @@ package com.databasir.core.domain.app.handler;
import com.databasir.core.domain.app.exception.DatabasirAuthenticationException;
import com.databasir.dao.impl.OauthAppDao;
import com.databasir.dao.impl.OauthAppPropertyDao;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@@ -19,12 +21,15 @@ public class OpenAuthHandlers {
private final OauthAppDao oauthAppDao;
private final OauthAppPropertyDao oauthAppPropertyDao;
public String authorizeUrl(String registrationId, Map<String, String[]> parameters) {
OauthApp app = oauthAppDao.selectByRegistrationId(registrationId);
List<OauthAppProperty> properties = oauthAppPropertyDao.selectByOauthAppId(app.getId());
return handlers.stream()
.filter(handler -> handler.support(app.getAppType()))
.findFirst()
.map(handler -> handler.authorizationUrl(app, parameters))
.map(handler -> handler.authorizationUrl(app, properties, parameters))
.orElseThrow();
}
@@ -34,10 +39,11 @@ public class OpenAuthHandlers {
var bizErr = REGISTRATION_ID_NOT_FOUND.exception("应用 ID [" + registrationId + "] 不存在");
return new DatabasirAuthenticationException(bizErr);
});
List<OauthAppProperty> properties = oauthAppPropertyDao.selectByOauthAppId(app.getId());
return handlers.stream()
.filter(handler -> handler.support(app.getAppType()))
.findFirst()
.map(handler -> handler.process(app, parameters))
.map(handler -> handler.process(app, properties, parameters))
.orElseThrow();
}
}

View File

@@ -0,0 +1,77 @@
package com.databasir.core.domain.app.handler;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.app.common.WeWorkProperties;
import com.databasir.core.infrastructure.remote.wework.WeWorkRemoteService;
import com.databasir.dao.enums.OAuthAppType;
import com.databasir.dao.tables.pojos.OauthApp;
import com.databasir.dao.tables.pojos.OauthAppProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
import java.util.Map;
import static com.databasir.core.domain.app.common.CommonProperties.INSTANCE;
@Component
@Slf4j
@RequiredArgsConstructor
public class WeWorkOpenAuthHandler implements OpenAuthHandler {
private final WeWorkRemoteService weWorkRemoteService;
@Override
public boolean support(OAuthAppType oauthAppType) {
return oauthAppType == OAuthAppType.WE_WORK;
}
@Override
public String authorizationUrl(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams) {
String authUrl = INSTANCE.getAuthHost(properties);
String authorizeUrl = authUrl + "/wwopen/sso/qrConnect";
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(authorizeUrl)
.queryParam("appid", INSTANCE.get(properties, WeWorkProperties.APP_ID))
.queryParam("agentid", INSTANCE.get(properties, WeWorkProperties.AGENT_ID))
.queryParam("redirect_uri", INSTANCE.get(properties, WeWorkProperties.REDIRECT_URL));
String url = builder
.encode()
.build()
.toUriString();
return url;
}
@Override
public OAuthProcessResult process(OauthApp app,
List<OauthAppProperty> properties,
Map<String, String[]> requestParams) {
if (!requestParams.containsKey("redirect_uri")) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception("缺少参数 redirect_uri", null);
}
String code = requestParams.get("code")[0];
String resourceUrl = INSTANCE.getResourceHost(properties);
String clientId = INSTANCE.get(properties, WeWorkProperties.APP_ID);
String secret = INSTANCE.get(properties, WeWorkProperties.SECRET);
String tokenUrl = resourceUrl + "/cgi-bin/gettoken";
String token = weWorkRemoteService.getToken(tokenUrl, clientId, secret);
String userIdUrl = resourceUrl + "/cgi-bin/auth/getuserinfo";
String userId = weWorkRemoteService.getUserId(userIdUrl, token, code);
String userInfoUrl = resourceUrl + "/cgi-bin/user/get";
JsonNode userInfo = weWorkRemoteService.getUserInfo(userInfoUrl, token, userId);
OAuthProcessResult result = new OAuthProcessResult();
result.setAvatar(userInfo.get("avatar").asText());
result.setEmail(userInfo.get("biz_mail").asText());
result.setNickname(userInfo.get("name").asText());
result.setUsername(userInfo.get("biz_mail").asText());
return result;
}
}

View File

@@ -0,0 +1,69 @@
package com.databasir.core.domain.app.validator;
import com.databasir.core.domain.DomainErrors;
import com.databasir.core.domain.app.data.OAuthAppCreateRequest;
import com.databasir.core.domain.app.data.OAuthAppPlatformResponse;
import com.databasir.core.domain.app.data.OAuthAppPlatformResponse.OAuthAppPlatformProperty;
import com.databasir.core.domain.app.data.OAuthAppUpdateRequest;
import com.databasir.core.domain.app.data.OauthAppPropertyData;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Component
@Slf4j
@RequiredArgsConstructor
public class OauthPropertiesValidator {
public void validate(OAuthAppCreateRequest request, List<OAuthAppPlatformResponse> platforms) {
Map<String, OauthAppPropertyData> propertyMapByName = request.getProperties()
.stream()
.collect(Collectors.toMap(OauthAppPropertyData::getName, i -> i));
platforms.stream()
.filter(platform -> platform.getAuthAppType() == request.getAppType())
.forEach(platform -> {
List<OAuthAppPlatformProperty> properties = platform.getProperties();
properties.forEach(property -> {
if (Objects.equals(true, property.getRequired())) {
if (!propertyMapByName.containsKey(property.getName())) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception(
property.getLabel() + " 不能为空");
}
if (StringUtils.isBlank(propertyMapByName.get(property.getName()).getValue())) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception(
property.getLabel() + " 不能为空");
}
}
});
});
}
public void validate(OAuthAppUpdateRequest request, List<OAuthAppPlatformResponse> platforms) {
Map<String, OauthAppPropertyData> propertyMapByName = request.getProperties()
.stream()
.collect(Collectors.toMap(OauthAppPropertyData::getName, i -> i));
platforms.stream()
.filter(platform -> platform.getAuthAppType() == request.getAppType())
.forEach(platform -> {
List<OAuthAppPlatformProperty> properties = platform.getProperties();
properties.forEach(property -> {
if (Objects.equals(true, property.getRequired())) {
if (!propertyMapByName.containsKey(property.getName())) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception(
property.getLabel() + " 不能为空");
}
if (StringUtils.isBlank(propertyMapByName.get(property.getName()).getValue())) {
throw DomainErrors.MISS_REQUIRED_PARAMETERS.exception(
property.getLabel() + " 不能为空");
}
}
});
});
}
}

View File

@@ -50,13 +50,17 @@ public class OperationLogService {
}
public void saveLoginFailedLog(String username, String msg) {
saveLoginFailedLog(username, "登录", msg);
}
public void saveLoginFailedLog(String username, String name, String msg) {
try {
JsonData result = JsonData.error("-1", Objects.requireNonNullElse(msg, "登录失败"));
OperationLogRequest log = OperationLogRequest.builder()
.isSuccess(false)
.operationCode("login")
.operationModule(AuditLog.Modules.LOGIN)
.operationName("登录")
.operationName(name)
.operatorNickname(username)
.operatorUsername(username)
.operatorUserId(-1)
@@ -70,6 +74,10 @@ public class OperationLogService {
}
public void saveLoginLog(User user, Boolean success, String msg) {
this.saveLoginLog(user, success, "登录", msg);
}
public void saveLoginLog(User user, Boolean success, String name, String msg) {
try {
JsonData result;
if (success) {
@@ -82,7 +90,7 @@ public class OperationLogService {
.involvedUserId(user.getId())
.operationCode("login")
.operationModule(AuditLog.Modules.LOGIN)
.operationName("登录")
.operationName(name)
.operatorNickname(user.getNickname())
.operatorUsername(user.getUsername())
.operatorUserId(user.getId())

View File

@@ -3,6 +3,7 @@ package com.databasir.core.infrastructure.remote;
import com.databasir.core.infrastructure.remote.github.GithubApiClient;
import com.databasir.core.infrastructure.remote.github.GithubOauthClient;
import com.databasir.core.infrastructure.remote.gitlab.GitlabApiClient;
import com.databasir.core.infrastructure.remote.wework.WeWorkApiClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
@@ -41,4 +42,13 @@ public class ClientConfig {
.build();
return retrofit.create(GitlabApiClient.class);
}
@Bean
public WeWorkApiClient weWorkApiClient() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://qyapi.weixin.qq.com")
.addConverterFactory(JacksonConverterFactory.create())
.build();
return retrofit.create(WeWorkApiClient.class);
}
}

View File

@@ -0,0 +1,25 @@
package com.databasir.core.infrastructure.remote.wework;
import com.fasterxml.jackson.databind.JsonNode;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.QueryMap;
import retrofit2.http.Url;
import java.util.Map;
public interface WeWorkApiClient {
@GET
@Headers(value = {
"Accept: application/json"
})
Call<JsonNode> getUserInfo(@Url String url, @QueryMap Map<String, String> request);
@GET
@Headers(value = {
"Accept: application/json"
})
Call<JsonNode> getAccessToken(@Url String url, @QueryMap Map<String, String> request);
}

View File

@@ -0,0 +1,65 @@
package com.databasir.core.infrastructure.remote.wework;
import com.databasir.common.SystemException;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import retrofit2.Call;
import retrofit2.Response;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
@RequiredArgsConstructor
public class WeWorkRemoteService {
private final WeWorkApiClient weWorkApiClient;
public String getToken(String url,
String corpId,
String secret) {
Map<String, String> map = new HashMap<>();
map.put("corpid", corpId);
map.put("corpsecret", secret);
JsonNode data = execute(weWorkApiClient.getAccessToken(url, map));
return data.get("access_token").asText();
}
public String getUserId(String url,
String accessToken,
String code) {
Map<String, String> map = new HashMap<>();
map.put("access_token", accessToken);
map.put("code", code);
return execute(weWorkApiClient.getUserInfo(url, map)).get("userid").asText();
}
public JsonNode getUserInfo(String url,
String accessToken,
String userId) {
Map<String, String> map = new HashMap<>();
map.put("access_token", accessToken);
map.put("userid", userId);
return execute(weWorkApiClient.getUserInfo(url, map));
}
private <T> T execute(Call<T> call) {
try {
Response<T> response = call.execute();
if (!response.isSuccessful()) {
log.error("request error: " + call.request() + ", response = " + response);
throw new SystemException("Call Remote Error");
} else {
log.info("response " + response);
T body = response.body();
return body;
}
} catch (IOException e) {
throw new SystemException("System Error", e);
}
}
}

View File

@@ -0,0 +1,108 @@
[
{
"authAppType": "GITLAB",
"authAppName": "Gitlab",
"properties": [
{
"name": "auth_host",
"label": "认证服务地址",
"description": "用于登录认证",
"required": true
},
{
"name": "resource_host",
"label": "资源服务地址",
"description": "用于用户信息等资源查询",
"required": true
},
{
"name": "client_id",
"label": "Client ID",
"description": "",
"required": true,
"stage": "AUTHORIZATION"
},
{
"name": "client_secret",
"label": "Client Secret",
"description": "",
"required": true
}
]
},
{
"authAppType": "GITHUB",
"authAppName": "Github",
"properties": [
{
"name": "auth_host",
"label": "认证服务地址",
"description": "用于登录认证",
"required": true
},
{
"name": "resource_host",
"label": "资源服务地址",
"description": "用于用户信息等资源查询",
"required": true
},
{
"name": "client_id",
"label": "Client ID",
"description": "",
"required": true
},
{
"name": "client_secret",
"label": "Client Secret",
"description": "",
"required": true
}
]
},
{
"authAppType": "WE_WORK",
"authAppName": "企业微信",
"properties": [
{
"name": "auth_host",
"label": "认证服务地址",
"description": "用于登录认证",
"required": true,
"defaultValue": "https://open.work.weixin.qq.com"
},
{
"name": "resource_host",
"label": "资源服务地址",
"description": "用于用户信息等资源查询",
"required": true,
"defaultValue": "https://qyapi.weixin.qq.com"
},
{
"name": "redirect_uri",
"label": "登录成功回跳地址",
"description": "",
"defaultValue": "javaScript:window.location.protocol + '//' +window.location.host+'/login/oauth2/'+formData.registrationId",
"required": true
},
{
"name": "appid",
"label": "企业 ID",
"description": "",
"required": true
},
{
"name": "agentid",
"label": "应用 agentID",
"description": "",
"required": true
},
{
"name": "secret",
"label": "应用 secret",
"description": "应用密钥",
"required": true
}
]
}
]