mirror of https://gitee.com/topiam/eiam
				
				
				
			
							parent
							
								
									25f55cf18b
								
							
						
					
					
						commit
						1774e0c056
					
				| 
						 | 
				
			
			@ -66,8 +66,7 @@
 | 
			
		|||
 | 
			
		||||
## 技术架构
 | 
			
		||||
 | 
			
		||||
- **后端
 | 
			
		||||
  **:[Spring Boot](https://spring.io/projects/spring-boot/) 、[Spring Security](https://spring.io/projects/spring-security/)
 | 
			
		||||
- **后端**:[Spring Boot](https://spring.io/projects/spring-boot/) 、[Spring Security](https://spring.io/projects/spring-security/)
 | 
			
		||||
- **前端**:[React.js](https://react.dev/) 、[Ant Design](https://ant.design)
 | 
			
		||||
- **中间件**:[MySQL](https://www.mysql.com/) 、[Redis](https://redis.io/)
 | 
			
		||||
- **基础设施**:[Docker](https://www.docker.com/)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
#
 | 
			
		||||
# TopIAM Employee - Employee Identity and Access Management
 | 
			
		||||
# TOPIAM Employee - 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
#
 | 
			
		||||
# TopIAM Employee - Employee Identity and Access Management
 | 
			
		||||
# TOPIAM Employee - 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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam-application</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>pom</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam-application</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,6 @@ import cn.topiam.employee.common.entity.app.AppAccountEntity;
 | 
			
		|||
import cn.topiam.employee.common.entity.app.AppEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppGroupAssociationEntity;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
import cn.topiam.employee.common.exception.app.AppAccountNotExistException;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppAccountRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppGroupAssociationRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,15 +41,24 @@ import lombok.extern.slf4j.Slf4j;
 | 
			
		|||
 * AbstractApplicationService
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/31 22:34
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/31 22:34
 | 
			
		||||
 */
 | 
			
		||||
@Slf4j
 | 
			
		||||
public abstract class AbstractApplicationService implements ApplicationService {
 | 
			
		||||
 | 
			
		||||
    protected final ObjectMapper mapper = new ObjectMapper();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取默认应用账户
 | 
			
		||||
     *
 | 
			
		||||
     * @param appId {@link String}
 | 
			
		||||
     * @param userId {@link String}
 | 
			
		||||
     * @return {@link AppAccount} AppAccount
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public AppAccount getAppAccount(Long appId, Long userId) {
 | 
			
		||||
        AppAccountEntity entity = appAccountRepository.findByAppIdAndUserId(appId, userId)
 | 
			
		||||
    public AppAccount getDefaultAppAccount(String appId, String userId) {
 | 
			
		||||
        AppAccountEntity entity = appAccountRepository
 | 
			
		||||
            .findByAppIdAndUserIdAndDefaultedIsTrue(appId, userId)
 | 
			
		||||
            .orElseThrow(AppAccountNotExistException::new);
 | 
			
		||||
        AppAccount account = new AppAccount();
 | 
			
		||||
        account.setAppId(entity.getAppId());
 | 
			
		||||
| 
						 | 
				
			
			@ -65,12 +73,11 @@ public abstract class AbstractApplicationService implements ApplicationService {
 | 
			
		|||
     * @param name              {@link String}
 | 
			
		||||
     * @param icon              {@link String}
 | 
			
		||||
     * @param remark            {@link String}
 | 
			
		||||
     * @param initLoginType     {@link InitLoginType}
 | 
			
		||||
     * @param authorizationType {@link AuthorizationType}
 | 
			
		||||
     * @return {@link AppEntity}
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public AppEntity createApp(String name, String icon, String remark, InitLoginType initLoginType,
 | 
			
		||||
    public AppEntity createApp(String name, String icon, String remark,
 | 
			
		||||
                               AuthorizationType authorizationType) {
 | 
			
		||||
        AppEntity appEntity = new AppEntity();
 | 
			
		||||
        appEntity.setName(name);
 | 
			
		||||
| 
						 | 
				
			
			@ -79,25 +86,25 @@ public abstract class AbstractApplicationService implements ApplicationService {
 | 
			
		|||
        appEntity.setTemplate(getCode());
 | 
			
		||||
        appEntity.setType(getType());
 | 
			
		||||
        appEntity.setEnabled(true);
 | 
			
		||||
        appEntity.setConfigured(false);
 | 
			
		||||
        appEntity.setProtocol(getProtocol());
 | 
			
		||||
        appEntity.setClientId(idGenerator.generateId().toString().replace("-", ""));
 | 
			
		||||
        appEntity.setClientSecret(idGenerator.generateId().toString().replace("-", ""));
 | 
			
		||||
        appEntity.setInitLoginType(initLoginType);
 | 
			
		||||
        appEntity.setAuthorizationType(authorizationType);
 | 
			
		||||
        appEntity.setRemark(remark);
 | 
			
		||||
        return appRepository.save(appEntity);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public AppEntity createApp(String name, String icon, String remark, List<String> groupIds,
 | 
			
		||||
                               InitLoginType initLoginType, AuthorizationType authorizationType) {
 | 
			
		||||
    public AppEntity createApp(String name, String icon, String remark, List<String> groups,
 | 
			
		||||
                               AuthorizationType authorizationType) {
 | 
			
		||||
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, initLoginType, authorizationType);
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, authorizationType);
 | 
			
		||||
        List<AppGroupAssociationEntity> list = new ArrayList<>();
 | 
			
		||||
        for (String id : groupIds) {
 | 
			
		||||
        for (String id : groups) {
 | 
			
		||||
            AppGroupAssociationEntity appGroupAssociationEntity = new AppGroupAssociationEntity();
 | 
			
		||||
            appGroupAssociationEntity.setGroupId(Long.valueOf(id));
 | 
			
		||||
            appGroupAssociationEntity.setAppId(appEntity.getId());
 | 
			
		||||
            appGroupAssociationEntity.setGroupId(id);
 | 
			
		||||
            appGroupAssociationEntity.setApp(appEntity);
 | 
			
		||||
            list.add(appGroupAssociationEntity);
 | 
			
		||||
        }
 | 
			
		||||
        appGroupAssociationRepository.saveAll(list);
 | 
			
		||||
| 
						 | 
				
			
			@ -109,16 +116,16 @@ public abstract class AbstractApplicationService implements ApplicationService {
 | 
			
		|||
     */
 | 
			
		||||
    protected final AppAccountRepository          appAccountRepository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AppGroupAssociationRepository
 | 
			
		||||
     */
 | 
			
		||||
    protected final AppGroupAssociationRepository appGroupAssociationRepository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ApplicationRepository
 | 
			
		||||
     */
 | 
			
		||||
    protected final AppRepository                 appRepository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AppGroupAssociationRepository
 | 
			
		||||
     */
 | 
			
		||||
    protected final AppGroupAssociationRepository appGroupAssociationRepository;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * IdGenerator
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -128,8 +135,8 @@ public abstract class AbstractApplicationService implements ApplicationService {
 | 
			
		|||
                                         AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                         AppRepository appRepository) {
 | 
			
		||||
        this.appAccountRepository = appAccountRepository;
 | 
			
		||||
        this.appRepository = appRepository;
 | 
			
		||||
        this.appGroupAssociationRepository = appGroupAssociationRepository;
 | 
			
		||||
        this.appRepository = appRepository;
 | 
			
		||||
        this.idGenerator = new AlternativeJdkIdGenerator();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,8 +32,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		|||
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppCertEntity;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AppCertUsingType;
 | 
			
		||||
import cn.topiam.employee.common.exception.app.AppCreateCertException;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.*;
 | 
			
		||||
import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		||||
import cn.topiam.employee.support.util.CertUtils;
 | 
			
		||||
import cn.topiam.employee.support.util.RsaUtils;
 | 
			
		||||
import static cn.topiam.employee.support.util.CertUtils.encodePem;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,21 +44,21 @@ import static cn.topiam.employee.support.util.RsaUtils.getKeys;
 | 
			
		|||
 * AbstractCertificateApplicationService
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/31 22:34
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/31 22:34
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractCertificateApplicationService extends AbstractApplicationService {
 | 
			
		||||
public abstract class AbstractCertApplicationService extends AbstractApplicationService {
 | 
			
		||||
    private final Logger         logger = LoggerFactory
 | 
			
		||||
        .getLogger(AbstractCertificateApplicationService.class);
 | 
			
		||||
        .getLogger(AbstractCertApplicationService.class);
 | 
			
		||||
    protected final ObjectMapper mapper = new ObjectMapper();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建证书
 | 
			
		||||
     *
 | 
			
		||||
     * @param appId     {@link Long}
 | 
			
		||||
     * @param appCode     {@link Long}
 | 
			
		||||
     * @param appId     {@link String}
 | 
			
		||||
     * @param appCode     {@link String}
 | 
			
		||||
     * @param usingType {@link AppCertUsingType}
 | 
			
		||||
     */
 | 
			
		||||
    public void createCertificate(Long appId, String appCode, AppCertUsingType usingType) {
 | 
			
		||||
    public void createCertificate(String appId, String appCode, AppCertUsingType usingType) {
 | 
			
		||||
        try {
 | 
			
		||||
            AppCertEntity config = new AppCertEntity();
 | 
			
		||||
            config.setAppId(appId);
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ public abstract class AbstractCertificateApplicationService extends AbstractAppl
 | 
			
		|||
            appCertRepository.save(config);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            logger.error("创建应用证书异常", e);
 | 
			
		||||
            throw new TopIamException(e.getMessage(), e);
 | 
			
		||||
            throw new AppCreateCertException();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -122,11 +122,11 @@ public abstract class AbstractCertificateApplicationService extends AbstractAppl
 | 
			
		|||
     */
 | 
			
		||||
    protected final IdGenerator               idGenerator;
 | 
			
		||||
 | 
			
		||||
    protected AbstractCertificateApplicationService(AppCertRepository appCertRepository,
 | 
			
		||||
                                                    AppAccountRepository appAccountRepository,
 | 
			
		||||
                                                    AppAccessPolicyRepository appAccessPolicyRepository,
 | 
			
		||||
                                                    AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                    AppRepository appRepository) {
 | 
			
		||||
    protected AbstractCertApplicationService(AppCertRepository appCertRepository,
 | 
			
		||||
                                             AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                             AppAccountRepository appAccountRepository,
 | 
			
		||||
                                             AppAccessPolicyRepository appAccessPolicyRepository,
 | 
			
		||||
                                             AppRepository appRepository) {
 | 
			
		||||
        super(appAccountRepository, appGroupAssociationRepository, appRepository);
 | 
			
		||||
        this.appCertRepository = appCertRepository;
 | 
			
		||||
        this.appAccessPolicyRepository = appAccessPolicyRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import lombok.experimental.SuperBuilder;
 | 
			
		|||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/7/13 21:32
 | 
			
		||||
 * Created by support@topiam.cn on 2023/7/13 21:32
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@SuperBuilder
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +42,12 @@ public class AbstractProtocolConfig implements Serializable {
 | 
			
		|||
    @NonNull
 | 
			
		||||
    private String            appId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 应用名称
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private String            appName;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 客户端ID
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ import lombok.Data;
 | 
			
		|||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/7/10 21:07
 | 
			
		||||
 * Created by support@topiam.cn on 2023/7/10 21:07
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
public class AppAccount implements Serializable {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,12 +36,12 @@ public class AppAccount implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * 应用ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long              appId;
 | 
			
		||||
    private String            appId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 用户ID
 | 
			
		||||
     */
 | 
			
		||||
    private Long              userId;
 | 
			
		||||
    private String            userId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 账户名称
 | 
			
		||||
| 
						 | 
				
			
			@ -52,4 +52,9 @@ public class AppAccount implements Serializable {
 | 
			
		|||
     * 账户密码
 | 
			
		||||
     */
 | 
			
		||||
    private String            password;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否默认
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean           defaulted;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,13 +28,12 @@ import cn.topiam.employee.common.entity.app.AppEntity;
 | 
			
		|||
import cn.topiam.employee.common.enums.app.AppProtocol;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AppType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 应用接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
public interface ApplicationService {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,9 +75,11 @@ public interface ApplicationService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 获取表单Schema
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@link Map}
 | 
			
		||||
     * @return {@link Object}
 | 
			
		||||
     */
 | 
			
		||||
    List<Map> getFormSchema();
 | 
			
		||||
    default Object getFormSchema() {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取base64图标
 | 
			
		||||
| 
						 | 
				
			
			@ -90,10 +91,10 @@ public interface ApplicationService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 创建应用
 | 
			
		||||
     *
 | 
			
		||||
     * @param name {@link String} 名称
 | 
			
		||||
     * @param icon {@link String} 图标
 | 
			
		||||
     * @param remark {@link String} 备注
 | 
			
		||||
     * @return {@link Long} 应用ID
 | 
			
		||||
     * @param name     {@link String} 名称
 | 
			
		||||
     * @param icon     {@link String} 图标
 | 
			
		||||
     * @param remark   {@link String} 备注
 | 
			
		||||
     * @return {@link String} 应用ID
 | 
			
		||||
     */
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    default String create(String name, String icon, String remark) {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,14 +104,14 @@ public interface ApplicationService {
 | 
			
		|||
    /**
 | 
			
		||||
     * 创建应用
 | 
			
		||||
     *
 | 
			
		||||
     * @param name {@link String} 名称
 | 
			
		||||
     * @param icon {@link String} 图标
 | 
			
		||||
     * @param remark {@link String} 备注
 | 
			
		||||
     * @param groupIds {@link String} 分组id
 | 
			
		||||
     * @return {@link Long} 应用ID
 | 
			
		||||
     * @param name     {@link String} 名称
 | 
			
		||||
     * @param icon     {@link String} 图标
 | 
			
		||||
     * @param remark   {@link String} 备注
 | 
			
		||||
     * @param groups {@link String} 应用分组
 | 
			
		||||
     * @return {@link String} 应用ID
 | 
			
		||||
     */
 | 
			
		||||
    @Transactional(rollbackFor = Exception.class)
 | 
			
		||||
    String create(String name, String icon, String remark, List<String> groupIds);
 | 
			
		||||
    String create(String name, String icon, String remark, List<String> groups);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除应用
 | 
			
		||||
| 
						 | 
				
			
			@ -137,13 +138,13 @@ public interface ApplicationService {
 | 
			
		|||
    Object getConfig(String appId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取应用用户信息
 | 
			
		||||
     * 获取默认应用用户信息
 | 
			
		||||
     *
 | 
			
		||||
     * @param appId {@link Long}
 | 
			
		||||
     * @param userId {@link Long}
 | 
			
		||||
     * @param appId {@link String}
 | 
			
		||||
     * @param userId {@link String}
 | 
			
		||||
     * @return {@link AppAccountEntity}
 | 
			
		||||
     */
 | 
			
		||||
    AppAccount getAppAccount(Long appId, Long userId);
 | 
			
		||||
    AppAccount getDefaultAppAccount(String appId, String userId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建应用
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +152,10 @@ public interface ApplicationService {
 | 
			
		|||
     * @param name {@link String}
 | 
			
		||||
     * @param icon  {@link String}
 | 
			
		||||
     * @param remark  {@link String}
 | 
			
		||||
     * @param initLoginType  {@link InitLoginType}
 | 
			
		||||
     * @param authorizationType {@link AuthorizationType}
 | 
			
		||||
     * @return {@link AppEntity}
 | 
			
		||||
     */
 | 
			
		||||
    AppEntity createApp(String name, String icon, String remark, InitLoginType initLoginType,
 | 
			
		||||
    AppEntity createApp(String name, String icon, String remark,
 | 
			
		||||
                        AuthorizationType authorizationType);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -164,11 +164,10 @@ public interface ApplicationService {
 | 
			
		|||
     * @param name {@link String}
 | 
			
		||||
     * @param icon  {@link String}
 | 
			
		||||
     * @param remark  {@link String}
 | 
			
		||||
     * @param groupIds {@link Long} 分组id
 | 
			
		||||
     * @param initLoginType  {@link InitLoginType}
 | 
			
		||||
     * @param groups {@link String} 应用分组
 | 
			
		||||
     * @param authorizationType {@link AuthorizationType}
 | 
			
		||||
     * @return {@link AppEntity}
 | 
			
		||||
     */
 | 
			
		||||
    AppEntity createApp(String name, String icon, String remark, List<String> groupIds,
 | 
			
		||||
                        InitLoginType initLoginType, AuthorizationType authorizationType);
 | 
			
		||||
    AppEntity createApp(String name, String icon, String remark, List<String> groups,
 | 
			
		||||
                        AuthorizationType authorizationType);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ import cn.topiam.employee.common.repository.app.AppRepository;
 | 
			
		|||
 * 应用服务加载器
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 21:08
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 21:08
 | 
			
		||||
 */
 | 
			
		||||
@Configuration
 | 
			
		||||
public class ApplicationServiceLoader implements ApplicationContextAware {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,9 +78,8 @@ public class ApplicationServiceLoader implements ApplicationContextAware {
 | 
			
		|||
     *
 | 
			
		||||
     * @return {@link List}
 | 
			
		||||
     */
 | 
			
		||||
    public Set<ApplicationService> getApplicationServiceList() {
 | 
			
		||||
        List<ApplicationService> values = loadMap.values().stream().toList();
 | 
			
		||||
        return new HashSet<>(values);
 | 
			
		||||
    public List<ApplicationService> getApplicationServiceList() {
 | 
			
		||||
        return loadMap.values().stream().toList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +110,7 @@ public class ApplicationServiceLoader implements ApplicationContextAware {
 | 
			
		|||
     */
 | 
			
		||||
    public ApplicationService getApplicationServiceByAppId(String appId) {
 | 
			
		||||
        AppRepository repository = applicationContext.getBean(AppRepository.class);
 | 
			
		||||
        Optional<AppEntity> optional = repository.findById(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppEntity> optional = repository.findById(appId);
 | 
			
		||||
        if (optional.isEmpty()) {
 | 
			
		||||
            throw new AppNotExistException();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,15 +23,15 @@ import java.util.Map;
 | 
			
		|||
 * 应用上下文
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/6/30 23:52
 | 
			
		||||
 * Created by support@topiam.cn on 2023/6/30 23:52
 | 
			
		||||
 */
 | 
			
		||||
public interface ApplicationContext {
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取应用ID
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@link Long}
 | 
			
		||||
     * @return {@link String}
 | 
			
		||||
     */
 | 
			
		||||
    Long getAppId();
 | 
			
		||||
    String getAppId();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取客户端ID
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ package cn.topiam.employee.application.context;
 | 
			
		|||
 * ApplicationContextHolder
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/10/29 22:37
 | 
			
		||||
 * Created by support@topiam.cn on 2022/10/29 22:37
 | 
			
		||||
 */
 | 
			
		||||
public final class ApplicationContextHolder {
 | 
			
		||||
    private static final ThreadLocal<ApplicationContext> HOLDER = new ThreadLocal<>();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		|||
 * 应用证书不存在
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/8 22:21
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:21
 | 
			
		||||
 */
 | 
			
		||||
public class AppCertNotExistException extends TopIamException {
 | 
			
		||||
    public AppCertNotExistException() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		|||
 * 应用配置不存在
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/8 22:21
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:21
 | 
			
		||||
 */
 | 
			
		||||
public class AppConfigNotExistException extends TopIamException {
 | 
			
		||||
    public AppConfigNotExistException() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * eiam-protocol-core - Employee Identity and Access Management
 | 
			
		||||
 * eiam-application-core - 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
 | 
			
		||||
| 
						 | 
				
			
			@ -15,18 +15,18 @@
 | 
			
		|||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.protocol.code.exception;
 | 
			
		||||
package cn.topiam.employee.application.exception;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 应用未配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/7/8 21:04
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:23
 | 
			
		||||
 */
 | 
			
		||||
public class TemplateNotExistException extends TopIamException {
 | 
			
		||||
 | 
			
		||||
    public TemplateNotExistException(Throwable throwable) {
 | 
			
		||||
        super("JWT模版不存在", throwable);
 | 
			
		||||
public class AppNotConfigException extends TopIamException {
 | 
			
		||||
    public AppNotConfigException() {
 | 
			
		||||
        super("app_not_config", "应用未配置", DEFAULT_STATUS);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		|||
 * 应用未启用
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/8 22:23
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:23
 | 
			
		||||
 */
 | 
			
		||||
public class AppNotEnableException extends TopIamException {
 | 
			
		||||
    public AppNotEnableException() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import cn.topiam.employee.support.exception.TopIamException;
 | 
			
		|||
 * 应用不存在异常
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/8 22:23
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:23
 | 
			
		||||
 */
 | 
			
		||||
public class AppNotExistException extends TopIamException {
 | 
			
		||||
    public AppNotExistException() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ import static org.springframework.http.HttpStatus.BAD_REQUEST;
 | 
			
		|||
 * 应用模版不存在
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/8 22:49
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/8 22:49
 | 
			
		||||
 */
 | 
			
		||||
public class AppTemplateNotExistException extends TopIamException {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam-application</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ import cn.topiam.employee.common.repository.app.AppRepository;
 | 
			
		|||
 * Form 应用配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/23 21:58
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/23 21:58
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractFormApplicationService extends AbstractApplicationService
 | 
			
		||||
                                                     implements FormApplicationService {
 | 
			
		||||
| 
						 | 
				
			
			@ -41,11 +41,11 @@ public abstract class AbstractFormApplicationService extends AbstractApplication
 | 
			
		|||
    @Override
 | 
			
		||||
    public void delete(String appId) {
 | 
			
		||||
        //删除应用
 | 
			
		||||
        appRepository.deleteById(Long.valueOf(appId));
 | 
			
		||||
        appRepository.deleteById(appId);
 | 
			
		||||
        //删除应用账户
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(Long.valueOf(appId));
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(appId);
 | 
			
		||||
        // 删除应用配置
 | 
			
		||||
        appFormConfigRepository.deleteByAppId(Long.valueOf(appId));
 | 
			
		||||
        appFormConfigRepository.deleteByAppId(appId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +61,7 @@ public abstract class AbstractFormApplicationService extends AbstractApplication
 | 
			
		|||
        configBuilder.clientId(configPo.getClientId());
 | 
			
		||||
        configBuilder.clientSecret(configPo.getClientSecret());
 | 
			
		||||
        configBuilder.appCode(configPo.getAppCode());
 | 
			
		||||
        configBuilder.appName(configPo.getAppName());
 | 
			
		||||
        configBuilder.appTemplate(configPo.getAppTemplate());
 | 
			
		||||
        configBuilder.loginUrl(configPo.getLoginUrl());
 | 
			
		||||
        configBuilder.usernameField(configPo.getUsernameField());
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +75,7 @@ public abstract class AbstractFormApplicationService extends AbstractApplication
 | 
			
		|||
        if (list != null) {
 | 
			
		||||
            configBuilder.otherField(new ArrayList<>(list));
 | 
			
		||||
        }
 | 
			
		||||
        configBuilder.configured(configPo.getConfigured());
 | 
			
		||||
        return configBuilder.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -83,8 +85,8 @@ public abstract class AbstractFormApplicationService extends AbstractApplication
 | 
			
		|||
    protected final AppFormConfigRepository appFormConfigRepository;
 | 
			
		||||
 | 
			
		||||
    protected AbstractFormApplicationService(AppRepository appRepository,
 | 
			
		||||
                                             AppAccountRepository appAccountRepository,
 | 
			
		||||
                                             AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                             AppAccountRepository appAccountRepository,
 | 
			
		||||
                                             AppFormConfigRepository appFormConfigRepository) {
 | 
			
		||||
        super(appAccountRepository, appGroupAssociationRepository, appRepository);
 | 
			
		||||
        this.appFormConfigRepository = appFormConfigRepository;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ import cn.topiam.employee.application.form.model.FormProtocolConfig;
 | 
			
		|||
 * 应用接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
public interface FormApplicationService extends ApplicationService {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,10 @@ import cn.topiam.employee.audit.context.AuditContext;
 | 
			
		|||
import cn.topiam.employee.common.entity.app.AppEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppFormConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.po.AppFormConfigPO;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.*;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AppProtocol;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AppType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormSubmitType;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppAccountRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppFormConfigRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppGroupAssociationRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +52,7 @@ import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKN
 | 
			
		|||
 * Form 用户应用
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Component
 | 
			
		||||
| 
						 | 
				
			
			@ -80,18 +83,18 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
        }
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
        //1、修改基本信息
 | 
			
		||||
        Optional<AppEntity> optional = appRepository.findById(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppEntity> optional = appRepository.findById(appId);
 | 
			
		||||
        if (optional.isEmpty()) {
 | 
			
		||||
            AuditContext.setContent("保存配置失败,应用 [" + appId + "] 不存在!");
 | 
			
		||||
            log.error(AuditContext.getContent());
 | 
			
		||||
            throw new AppNotExistException();
 | 
			
		||||
        }
 | 
			
		||||
        AppEntity appEntity = optional.get();
 | 
			
		||||
        appEntity.setAuthorizationType(model.getAuthorizationType());
 | 
			
		||||
        appEntity.setConfigured(true);
 | 
			
		||||
        appEntity.setInitLoginUrl(model.getInitLoginUrl());
 | 
			
		||||
        appRepository.save(appEntity);
 | 
			
		||||
        //2、修改 表单代填 配置
 | 
			
		||||
        Optional<AppFormConfigEntity> form = appFormConfigRepository
 | 
			
		||||
            .findByAppId(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppFormConfigEntity> form = appFormConfigRepository.findByAppId(appId);
 | 
			
		||||
        if (form.isEmpty()) {
 | 
			
		||||
            AuditContext.setContent("保存配置失败,应用 [" + appId + "] 不存在!");
 | 
			
		||||
            log.error(AuditContext.getContent());
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +108,6 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
        formConfig.setRemark(entity.getRemark());
 | 
			
		||||
        formConfig.setCreateBy(entity.getCreateBy());
 | 
			
		||||
        formConfig.setCreateTime(entity.getCreateTime());
 | 
			
		||||
        formConfig.setDeleted(entity.getDeleted());
 | 
			
		||||
        appFormConfigRepository.save(formConfig);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +119,7 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Object getConfig(String appId) {
 | 
			
		||||
        AppFormConfigPO po = appFormConfigRepository.getByAppId(Long.valueOf(appId));
 | 
			
		||||
        AppFormConfigPO po = appFormConfigRepository.getByAppId(appId);
 | 
			
		||||
        return appFormConfigConverter.entityConverterToFormConfigResult(po);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +150,7 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String getDescription() {
 | 
			
		||||
        return "表单代填可以模拟用户在登录页输入用户名和密码,再通过表单提交的一种登录方式。应用的账号密码在 TopIAM 中使用 AES256 加密算法本地加密存储。很多旧系统、不支持标准认证协议的系统或不支持改造的系统可以使用表单代填实现统一身份管理。表单中有图片验证码、CSRF token、动态参数的场景不适用。";
 | 
			
		||||
        return "表单代填可以模拟用户在登录页输入用户名和密码,再通过表单提交的一种登录方式。应用的账号密码在 TOPIAM 中使用 AES256 加密算法本地加密存储。很多旧系统、不支持标准认证协议的系统或不支持改造的系统可以使用表单代填实现统一身份管理。表单中有图片验证码、CSRF token、动态参数的场景不适用。";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -171,16 +173,6 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
        return AppProtocol.FORM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取表单Schema
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@link Map}
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Map> getFormSchema() {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取base64图标
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -194,15 +186,15 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
    /**
 | 
			
		||||
     * 创建应用
 | 
			
		||||
     *
 | 
			
		||||
     * @param name   {@link String} 名称
 | 
			
		||||
     * @param icon   {@link String} 图标
 | 
			
		||||
     * @param remark {@link String} 备注
 | 
			
		||||
     * @param groupIds {@link Long} 分组id
 | 
			
		||||
     * @param name     {@link String} 名称
 | 
			
		||||
     * @param icon     {@link String} 图标
 | 
			
		||||
     * @param remark   {@link String} 备注
 | 
			
		||||
     * @param groups {@link String} 应用分组
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String create(String name, String icon, String remark, List<String> groupIds) {
 | 
			
		||||
    public String create(String name, String icon, String remark, List<String> groups) {
 | 
			
		||||
        //1、创建应用
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, groupIds, InitLoginType.PORTAL_OR_APP,
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, groups,
 | 
			
		||||
            AuthorizationType.AUTHORIZATION);
 | 
			
		||||
        AppFormConfigEntity appFormConfig = new AppFormConfigEntity();
 | 
			
		||||
        appFormConfig.setAppId(appEntity.getId());
 | 
			
		||||
| 
						 | 
				
			
			@ -215,11 +207,11 @@ public class FormStandardApplicationServiceImpl extends AbstractFormApplicationS
 | 
			
		|||
    private final AppFormConfigConverter appFormConfigConverter;
 | 
			
		||||
 | 
			
		||||
    protected FormStandardApplicationServiceImpl(AppAccountRepository appAccountRepository,
 | 
			
		||||
                                                 AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                 AppFormConfigRepository appFormConfigRepository,
 | 
			
		||||
                                                 AppRepository appRepository,
 | 
			
		||||
                                                 AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                 AppFormConfigConverter appFormConfigConverter) {
 | 
			
		||||
        super(appRepository, appAccountRepository, appGroupAssociationRepository,
 | 
			
		||||
        super(appRepository, appGroupAssociationRepository, appAccountRepository,
 | 
			
		||||
            appFormConfigRepository);
 | 
			
		||||
        this.appFormConfigConverter = appFormConfigConverter;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,8 @@ import cn.topiam.employee.application.form.pojo.AppFormProtocolEndpoint;
 | 
			
		|||
import cn.topiam.employee.application.form.pojo.AppFormSaveConfigParam;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppFormConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.po.AppFormConfigPO;
 | 
			
		||||
import cn.topiam.employee.core.help.ServerHelp;
 | 
			
		||||
import static cn.topiam.employee.common.constant.AppConstants.APP_CODE;
 | 
			
		||||
import cn.topiam.employee.core.context.ContextService;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.APP_CODE;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.FormEndpointConstants.FORM_SSO_PATH;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ public interface AppFormConfigConverter {
 | 
			
		|||
     * @param config {@link AppFormSaveConfigParam}
 | 
			
		||||
     * @return {@link AppFormConfigEntity}
 | 
			
		||||
     */
 | 
			
		||||
    @Mapping(target = "deleted", ignore = true)
 | 
			
		||||
 | 
			
		||||
    @Mapping(target = "updateTime", ignore = true)
 | 
			
		||||
    @Mapping(target = "updateBy", ignore = true)
 | 
			
		||||
    @Mapping(target = "remark", ignore = true)
 | 
			
		||||
| 
						 | 
				
			
			@ -72,11 +72,9 @@ public interface AppFormConfigConverter {
 | 
			
		|||
        }
 | 
			
		||||
        AppFormConfigGetResult result = new AppFormConfigGetResult();
 | 
			
		||||
        if (po.getAppId() != null) {
 | 
			
		||||
            result.setAppId(String.valueOf(po.getAppId()));
 | 
			
		||||
            result.setAppId(po.getAppId());
 | 
			
		||||
        }
 | 
			
		||||
        result.setInitLoginType(po.getInitLoginType());
 | 
			
		||||
        result.setInitLoginUrl(po.getInitLoginUrl());
 | 
			
		||||
        result.setAuthorizationType(po.getAuthorizationType());
 | 
			
		||||
        result.setLoginUrl(po.getLoginUrl());
 | 
			
		||||
        result.setUsernameField(po.getUsernameField());
 | 
			
		||||
        result.setPasswordField(po.getPasswordField());
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +104,7 @@ public interface AppFormConfigConverter {
 | 
			
		|||
        variables.put(APP_CODE,appCode);
 | 
			
		||||
        StringSubstitutor sub = new StringSubstitutor(variables, "{", "}");
 | 
			
		||||
        //IDP SSO 端点
 | 
			
		||||
        domain.setIdpSsoEndpoint(sub.replace(ServerHelp.getPortalPublicBaseUrl()+FORM_SSO_PATH));
 | 
			
		||||
        domain.setIdpSsoEndpoint(sub.replace(ContextService.getPortalPublicBaseUrl()+FORM_SSO_PATH));
 | 
			
		||||
        return domain;
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,8 @@ package cn.topiam.employee.application.form.model;
 | 
			
		|||
import java.io.Serial;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.AbstractProtocolConfig;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppFormConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormEncryptType;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,18 +30,16 @@ import cn.topiam.employee.common.enums.app.FormSubmitType;
 | 
			
		|||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.experimental.SuperBuilder;
 | 
			
		||||
import lombok.extern.jackson.Jacksonized;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form 协议配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/28 21:43
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/28 21:43
 | 
			
		||||
 */
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
@SuperBuilder
 | 
			
		||||
@Jacksonized
 | 
			
		||||
public class FormProtocolConfig extends AbstractProtocolConfig {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
| 
						 | 
				
			
			@ -89,4 +89,13 @@ public class FormProtocolConfig extends AbstractProtocolConfig {
 | 
			
		|||
     * 登录其他信息
 | 
			
		||||
     */
 | 
			
		||||
    private List<AppFormConfigEntity.OtherField> otherField;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否配置
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean                              configured;
 | 
			
		||||
 | 
			
		||||
    public List<AppFormConfigEntity.OtherField> getOtherField() {
 | 
			
		||||
        return CollectionUtils.isEmpty(otherField) ? List.of() : otherField;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,8 @@ import java.io.Serializable;
 | 
			
		|||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppFormConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormEncryptType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormSubmitType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +32,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		|||
 * Form 配置返回
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/5/31 22:46
 | 
			
		||||
 * Created by support@topiam.cn on 2022/5/31 22:46
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "Form 配置返回响应")
 | 
			
		||||
| 
						 | 
				
			
			@ -45,24 +43,12 @@ public class AppFormConfigGetResult implements Serializable {
 | 
			
		|||
    @Schema(description = "应用id")
 | 
			
		||||
    private String                               appId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 发起方
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "SSO 发起方")
 | 
			
		||||
    private InitLoginType                        initLoginType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 登录链接
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "SSO 登录链接")
 | 
			
		||||
    private String                               initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权范围
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "SSO 授权范围")
 | 
			
		||||
    private AuthorizationType                    authorizationType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录URL
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,14 +22,13 @@ import java.io.Serializable;
 | 
			
		|||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* 协议端点域
 | 
			
		||||
*
 | 
			
		||||
* @author TopIAM
 | 
			
		||||
* Created by support@topiam.cn on  2022/6/4 23:37
 | 
			
		||||
* Created by support@topiam.cn on 2022/6/4 23:37
 | 
			
		||||
*/
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "协议端点")
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +40,6 @@ public class AppFormProtocolEndpoint implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * IDP SSO 端点
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "IDP SSO 端点")
 | 
			
		||||
    @Schema(description = "IDP SSO 端点")
 | 
			
		||||
    private String            idpSsoEndpoint;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import java.io.Serializable;
 | 
			
		|||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppFormConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormEncryptType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.FormSubmitType;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +33,7 @@ import jakarta.validation.constraints.NotNull;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/12/13 22:45
 | 
			
		||||
 * Created by support@topiam.cn on 2022/12/13 22:45
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "保存 表单代填 应用配置参数")
 | 
			
		||||
| 
						 | 
				
			
			@ -44,11 +43,10 @@ public class AppFormSaveConfigParam implements Serializable {
 | 
			
		|||
    private static final long                    serialVersionUID = 7257798528680745281L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO范围
 | 
			
		||||
     * 登录发起登录URL
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SSO范围不能为空")
 | 
			
		||||
    @Schema(description = "SSO范围")
 | 
			
		||||
    private AuthorizationType                    authorizationType;
 | 
			
		||||
    @Schema(description = "登录发起登录URL")
 | 
			
		||||
    private String                               initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登录URL
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam-application</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ package cn.topiam.employee.application.jwt;
 | 
			
		|||
import java.util.Objects;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.AbstractCertificateApplicationService;
 | 
			
		||||
import cn.topiam.employee.application.AbstractCertApplicationService;
 | 
			
		||||
import cn.topiam.employee.application.exception.AppCertNotExistException;
 | 
			
		||||
import cn.topiam.employee.application.exception.AppNotExistException;
 | 
			
		||||
import cn.topiam.employee.application.jwt.model.JwtProtocolConfig;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,11 +33,10 @@ import cn.topiam.employee.common.repository.app.*;
 | 
			
		|||
 * JWT 应用配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/23 21:58
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/23 21:58
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractJwtCertificateApplicationService extends
 | 
			
		||||
                                                               AbstractCertificateApplicationService
 | 
			
		||||
                                                               implements JwtApplicationService {
 | 
			
		||||
public abstract class AbstractJwtApplicationService extends AbstractCertApplicationService
 | 
			
		||||
                                                    implements JwtApplicationService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * AppCertRepository
 | 
			
		||||
| 
						 | 
				
			
			@ -53,13 +52,13 @@ public abstract class AbstractJwtCertificateApplicationService extends
 | 
			
		|||
    @Override
 | 
			
		||||
    public void delete(String appId) {
 | 
			
		||||
        //删除应用
 | 
			
		||||
        appRepository.deleteById(Long.valueOf(appId));
 | 
			
		||||
        appRepository.deleteById(appId);
 | 
			
		||||
        //删除应用账户
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(Long.valueOf(appId));
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(appId);
 | 
			
		||||
        // 删除应用配置
 | 
			
		||||
        appJwtConfigRepository.deleteByAppId(Long.valueOf(appId));
 | 
			
		||||
        appJwtConfigRepository.deleteByAppId(appId);
 | 
			
		||||
        // 删除证书
 | 
			
		||||
        appCertRepository.deleteByAppId(Long.valueOf(appId));
 | 
			
		||||
        appCertRepository.deleteByAppId(appId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -68,15 +67,11 @@ public abstract class AbstractJwtCertificateApplicationService extends
 | 
			
		|||
        if (Objects.isNull(configPo)) {
 | 
			
		||||
            throw new AppNotExistException();
 | 
			
		||||
        }
 | 
			
		||||
        Optional<AppCertEntity> appCertEntity = appCertRepository
 | 
			
		||||
        Optional<AppCertEntity> entity = appCertRepository
 | 
			
		||||
            .findByAppIdAndUsingType(configPo.getAppId(), AppCertUsingType.JWT_ENCRYPT);
 | 
			
		||||
        if (appCertEntity.isEmpty()) {
 | 
			
		||||
        if (entity.isEmpty()) {
 | 
			
		||||
            throw new AppCertNotExistException();
 | 
			
		||||
        }
 | 
			
		||||
        appCertEntity.ifPresent(appCert -> {
 | 
			
		||||
            configPo.setJwtPrivateKey(appCert.getPrivateKey());
 | 
			
		||||
            configPo.setJwtPublicKey(appCert.getPublicKey());
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        JwtProtocolConfig.JwtProtocolConfigBuilder<?, ?> jwtProtocolConfig = JwtProtocolConfig
 | 
			
		||||
            .builder();
 | 
			
		||||
| 
						 | 
				
			
			@ -84,28 +79,33 @@ public abstract class AbstractJwtCertificateApplicationService extends
 | 
			
		|||
        //@formatter:off
 | 
			
		||||
        jwtProtocolConfig.appId(String.valueOf(configPo.getAppId()))
 | 
			
		||||
            .clientId(configPo.getClientId())
 | 
			
		||||
            .appName(configPo.getAppName())
 | 
			
		||||
            .clientSecret(configPo.getClientSecret())
 | 
			
		||||
            .appCode(configPo.getAppCode())
 | 
			
		||||
            .appTemplate(configPo.getAppTemplate())
 | 
			
		||||
            .redirectUrl(configPo.getRedirectUrl())
 | 
			
		||||
            .targetLinkUrl(configPo.getTargetLinkUrl())
 | 
			
		||||
            .bindingType(configPo.getBindingType())
 | 
			
		||||
            .idTokenTimeToLive(configPo.getIdTokenTimeToLive())
 | 
			
		||||
            .jwtPublicKey(configPo.getJwtPublicKey())
 | 
			
		||||
            .jwtPrivateKey(configPo.getJwtPrivateKey())
 | 
			
		||||
            .idTokenSubjectType(configPo.getIdTokenSubjectType());
 | 
			
		||||
            .idTokenTimeToLive(Objects.toString(configPo.getIdTokenTimeToLive().toSeconds(),""))
 | 
			
		||||
            .idTokenSubjectType(configPo.getIdTokenSubjectType())
 | 
			
		||||
            .configured(configPo.getConfigured());
 | 
			
		||||
 | 
			
		||||
        entity.ifPresent(appCert -> {
 | 
			
		||||
            jwtProtocolConfig.jwtPrivateKey(appCert.getPrivateKey());
 | 
			
		||||
            jwtProtocolConfig.jwtPublicKey(appCert.getPublicKey());
 | 
			
		||||
        });
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
        return jwtProtocolConfig.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected AbstractJwtCertificateApplicationService(AppJwtConfigRepository appJwtConfigRepository,
 | 
			
		||||
                                                       AppCertRepository appCertRepository,
 | 
			
		||||
                                                       AppRepository appRepository,
 | 
			
		||||
                                                       AppAccountRepository appAccountRepository,
 | 
			
		||||
                                                       AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                       AppAccessPolicyRepository appAccessPolicyRepository) {
 | 
			
		||||
        super(appCertRepository, appAccountRepository, appAccessPolicyRepository,
 | 
			
		||||
            appGroupAssociationRepository, appRepository);
 | 
			
		||||
    protected AbstractJwtApplicationService(AppJwtConfigRepository appJwtConfigRepository,
 | 
			
		||||
                                            AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                            AppCertRepository appCertRepository,
 | 
			
		||||
                                            AppRepository appRepository,
 | 
			
		||||
                                            AppAccountRepository appAccountRepository,
 | 
			
		||||
                                            AppAccessPolicyRepository appAccessPolicyRepository) {
 | 
			
		||||
        super(appCertRepository, appGroupAssociationRepository, appAccountRepository,
 | 
			
		||||
            appAccessPolicyRepository, appRepository);
 | 
			
		||||
        this.appCertRepository = appCertRepository;
 | 
			
		||||
        this.appRepository = appRepository;
 | 
			
		||||
        this.appJwtConfigRepository = appJwtConfigRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ import cn.topiam.employee.application.jwt.model.JwtProtocolConfig;
 | 
			
		|||
 * 应用接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
public interface JwtApplicationService extends ApplicationService {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.application.jwt;
 | 
			
		||||
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +30,6 @@ import cn.topiam.employee.application.exception.AppNotExistException;
 | 
			
		|||
import cn.topiam.employee.application.jwt.converter.AppJwtConfigConverter;
 | 
			
		||||
import cn.topiam.employee.application.jwt.pojo.AppJwtSaveConfigParam;
 | 
			
		||||
import cn.topiam.employee.audit.context.AuditContext;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppCertEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppJwtConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.po.AppJwtConfigPO;
 | 
			
		||||
| 
						 | 
				
			
			@ -44,20 +44,18 @@ import lombok.extern.slf4j.Slf4j;
 | 
			
		|||
import jakarta.validation.ConstraintViolationException;
 | 
			
		||||
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
 | 
			
		||||
 | 
			
		||||
import static cn.topiam.employee.common.enums.app.InitLoginType.PORTAL_OR_APP;
 | 
			
		||||
import static cn.topiam.employee.support.repository.domain.BaseEntity.LAST_MODIFIED_BY;
 | 
			
		||||
import static cn.topiam.employee.support.repository.domain.BaseEntity.LAST_MODIFIED_TIME;
 | 
			
		||||
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
 | 
			
		||||
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * JWT 用户应用
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		||||
                                                          AbstractJwtCertificateApplicationService {
 | 
			
		||||
public class JwtStandardApplicationServiceImpl extends AbstractJwtApplicationService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新应用配置
 | 
			
		||||
| 
						 | 
				
			
			@ -84,18 +82,18 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
        }
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
        //1、修改基本信息
 | 
			
		||||
        Optional<AppEntity> optional = appRepository.findById(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppEntity> optional = appRepository.findById(appId);
 | 
			
		||||
        if (optional.isEmpty()) {
 | 
			
		||||
            AuditContext.setContent("保存配置失败,应用 [" + appId + "] 不存在!");
 | 
			
		||||
            log.error(AuditContext.getContent());
 | 
			
		||||
            throw new AppNotExistException();
 | 
			
		||||
        }
 | 
			
		||||
        AppEntity appEntity = optional.get();
 | 
			
		||||
        appEntity.setAuthorizationType(model.getAuthorizationType());
 | 
			
		||||
        appEntity.setInitLoginType(PORTAL_OR_APP);
 | 
			
		||||
        appEntity.setInitLoginUrl(model.getInitLoginUrl());
 | 
			
		||||
        appEntity.setConfigured(true);
 | 
			
		||||
        appRepository.save(appEntity);
 | 
			
		||||
        //2、修改 JWT 配置
 | 
			
		||||
        Optional<AppJwtConfigEntity> jwt = appJwtConfigRepository.findByAppId(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppJwtConfigEntity> jwt = appJwtConfigRepository.findByAppId(appId);
 | 
			
		||||
        if (jwt.isEmpty()) {
 | 
			
		||||
            AuditContext.setContent("保存配置失败,应用 [" + appId + "] 不存在!");
 | 
			
		||||
            log.error(AuditContext.getContent());
 | 
			
		||||
| 
						 | 
				
			
			@ -115,13 +113,7 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public Object getConfig(String appId) {
 | 
			
		||||
        AppJwtConfigPO configPo = appJwtConfigRepository.getByAppId(Long.valueOf(appId));
 | 
			
		||||
        Optional<AppCertEntity> appCertEntity = appCertRepository
 | 
			
		||||
            .findByAppIdAndUsingType(configPo.getAppId(), AppCertUsingType.JWT_ENCRYPT);
 | 
			
		||||
        appCertEntity.ifPresent(appCert -> {
 | 
			
		||||
            configPo.setJwtPrivateKey(appCert.getPrivateKey());
 | 
			
		||||
            configPo.setJwtPublicKey(appCert.getPublicKey());
 | 
			
		||||
        });
 | 
			
		||||
        AppJwtConfigPO configPo = appJwtConfigRepository.getByAppId(appId);
 | 
			
		||||
        return appJwtConfigConverter.entityConverterToFormConfigResult(configPo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -175,16 +167,6 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
        return AppProtocol.JWT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取表单Schema
 | 
			
		||||
     *
 | 
			
		||||
     * @return {@link Map}
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Map> getFormSchema() {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取base64图标
 | 
			
		||||
     *
 | 
			
		||||
| 
						 | 
				
			
			@ -198,15 +180,15 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
    /**
 | 
			
		||||
     * 创建应用
 | 
			
		||||
     *
 | 
			
		||||
     * @param name   {@link String} 名称
 | 
			
		||||
     * @param icon   {@link String} 图标
 | 
			
		||||
     * @param remark {@link String} 备注
 | 
			
		||||
     * @param groupIds {@link Long} 分组id
 | 
			
		||||
     * @param name     {@link String} 名称
 | 
			
		||||
     * @param icon     {@link String} 图标
 | 
			
		||||
     * @param remark   {@link String} 备注
 | 
			
		||||
     * @param groups {@link String} 应用分组
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public String create(String name, String icon, String remark, List<String> groupIds) {
 | 
			
		||||
    public String create(String name, String icon, String remark, List<String> groups) {
 | 
			
		||||
        //1、创建应用
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, groupIds, InitLoginType.PORTAL_OR_APP,
 | 
			
		||||
        AppEntity appEntity = createApp(name, icon, remark, groups,
 | 
			
		||||
            AuthorizationType.AUTHORIZATION);
 | 
			
		||||
        //jwt配置
 | 
			
		||||
        AppJwtConfigEntity jwtConfigEntity = new AppJwtConfigEntity();
 | 
			
		||||
| 
						 | 
				
			
			@ -214,8 +196,8 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
        jwtConfigEntity.setBindingType(JwtBindingType.POST);
 | 
			
		||||
        //id_token sub 类型
 | 
			
		||||
        jwtConfigEntity.setIdTokenSubjectType(JwtIdTokenSubjectType.USER_ID);
 | 
			
		||||
        //token有效期
 | 
			
		||||
        jwtConfigEntity.setIdTokenTimeToLive(600);
 | 
			
		||||
        //token有效期(秒)
 | 
			
		||||
        jwtConfigEntity.setIdTokenTimeToLive(Duration.ofSeconds(600));
 | 
			
		||||
        appJwtConfigRepository.save(jwtConfigEntity);
 | 
			
		||||
        // 创建RSA证书
 | 
			
		||||
        createCertificate(appEntity.getId(), appEntity.getCode(), AppCertUsingType.JWT_ENCRYPT);
 | 
			
		||||
| 
						 | 
				
			
			@ -224,15 +206,15 @@ public class JwtStandardCertificateApplicationServiceImpl extends
 | 
			
		|||
 | 
			
		||||
    private final AppJwtConfigConverter appJwtConfigConverter;
 | 
			
		||||
 | 
			
		||||
    public JwtStandardCertificateApplicationServiceImpl(AppJwtConfigRepository appJwtConfigRepository,
 | 
			
		||||
                                                        AppJwtConfigConverter appJwtConfigConverter,
 | 
			
		||||
                                                        AppCertRepository appCertRepository,
 | 
			
		||||
                                                        AppRepository appRepository,
 | 
			
		||||
                                                        AppAccountRepository appAccountRepository,
 | 
			
		||||
                                                        AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                        AppAccessPolicyRepository appAccessPolicyRepository) {
 | 
			
		||||
        super(appJwtConfigRepository, appCertRepository, appRepository, appAccountRepository,
 | 
			
		||||
            appGroupAssociationRepository, appAccessPolicyRepository);
 | 
			
		||||
    public JwtStandardApplicationServiceImpl(AppJwtConfigRepository appJwtConfigRepository,
 | 
			
		||||
                                             AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                             AppJwtConfigConverter appJwtConfigConverter,
 | 
			
		||||
                                             AppCertRepository appCertRepository,
 | 
			
		||||
                                             AppRepository appRepository,
 | 
			
		||||
                                             AppAccountRepository appAccountRepository,
 | 
			
		||||
                                             AppAccessPolicyRepository appAccessPolicyRepository) {
 | 
			
		||||
        super(appJwtConfigRepository, appGroupAssociationRepository, appCertRepository,
 | 
			
		||||
            appRepository, appAccountRepository, appAccessPolicyRepository);
 | 
			
		||||
        this.appJwtConfigConverter = appJwtConfigConverter;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,21 +17,21 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.application.jwt.converter;
 | 
			
		||||
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.text.StringSubstitutor;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.Mapping;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.jwt.pojo.AppJwtConfigGetResult;
 | 
			
		||||
import cn.topiam.employee.application.jwt.pojo.AppJwtProtocolEndpoint;
 | 
			
		||||
import cn.topiam.employee.application.jwt.pojo.AppJwtSaveConfigParam;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppJwtConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.po.AppJwtConfigPO;
 | 
			
		||||
import cn.topiam.employee.core.help.ServerHelp;
 | 
			
		||||
import static cn.topiam.employee.common.constant.AppConstants.APP_CODE;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.JwtEndpointConstants.JWT_SLO_PATH;
 | 
			
		||||
import cn.topiam.employee.core.context.ContextService;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.APP_CODE;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.JwtEndpointConstants.JWT_SSO_PATH;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -49,15 +49,19 @@ public interface AppJwtConfigConverter {
 | 
			
		|||
     * @param config {@link AppJwtSaveConfigParam}
 | 
			
		||||
     * @return {@link AppJwtConfigEntity}
 | 
			
		||||
     */
 | 
			
		||||
    @Mapping(target = "deleted", ignore = true)
 | 
			
		||||
    @Mapping(target = "updateTime", ignore = true)
 | 
			
		||||
    @Mapping(target = "updateBy", ignore = true)
 | 
			
		||||
    @Mapping(target = "remark", ignore = true)
 | 
			
		||||
    @Mapping(target = "id", ignore = true)
 | 
			
		||||
    @Mapping(target = "createTime", ignore = true)
 | 
			
		||||
    @Mapping(target = "createBy", ignore = true)
 | 
			
		||||
    @Mapping(target = "appId", ignore = true)
 | 
			
		||||
    AppJwtConfigEntity appJwtSaveConfigParamToEntity(AppJwtSaveConfigParam config);
 | 
			
		||||
    default AppJwtConfigEntity appJwtSaveConfigParamToEntity(AppJwtSaveConfigParam config) {
 | 
			
		||||
        if (config == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AppJwtConfigEntity entity = new AppJwtConfigEntity();
 | 
			
		||||
        entity.setRedirectUrl(config.getRedirectUrl());
 | 
			
		||||
        entity.setTargetLinkUrl(config.getTargetLinkUrl());
 | 
			
		||||
        entity.setBindingType(config.getBindingType());
 | 
			
		||||
        entity.setIdTokenSubjectType(config.getIdTokenSubjectType());
 | 
			
		||||
        entity.setIdTokenTimeToLive(Duration.ofSeconds(config.getIdTokenTimeToLive()));
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * po 转 result
 | 
			
		||||
| 
						 | 
				
			
			@ -71,16 +75,14 @@ public interface AppJwtConfigConverter {
 | 
			
		|||
        }
 | 
			
		||||
        AppJwtConfigGetResult result = new AppJwtConfigGetResult();
 | 
			
		||||
        if (po.getAppId() != null) {
 | 
			
		||||
            result.setAppId(String.valueOf(po.getAppId()));
 | 
			
		||||
            result.setAppId(po.getAppId());
 | 
			
		||||
        }
 | 
			
		||||
        result.setInitLoginType(po.getInitLoginType());
 | 
			
		||||
        result.setInitLoginUrl(po.getInitLoginUrl());
 | 
			
		||||
        result.setAuthorizationType(po.getAuthorizationType());
 | 
			
		||||
        result.setRedirectUrl(po.getRedirectUrl());
 | 
			
		||||
        result.setTargetLinkUrl(po.getTargetLinkUrl());
 | 
			
		||||
        result.setBindingType(po.getBindingType());
 | 
			
		||||
        result.setIdTokenSubjectType(po.getIdTokenSubjectType());
 | 
			
		||||
        result.setIdTokenTimeToLive(po.getIdTokenTimeToLive());
 | 
			
		||||
        result.setIdTokenTimeToLive(Objects.toString(po.getIdTokenTimeToLive().toSeconds(), ""));
 | 
			
		||||
        result.setProtocolEndpoint(getProtocolEndpointDomain(po.getAppCode()));
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -98,9 +100,7 @@ public interface AppJwtConfigConverter {
 | 
			
		|||
        variables.put(APP_CODE,appCode);
 | 
			
		||||
        StringSubstitutor sub = new StringSubstitutor(variables, "{", "}");
 | 
			
		||||
        //IDP SSO 端点
 | 
			
		||||
        domain.setIdpSsoEndpoint(sub.replace(ServerHelp.getPortalPublicBaseUrl()+JWT_SSO_PATH));
 | 
			
		||||
        //IDP SLO 端点
 | 
			
		||||
        domain.setIdpSloEndpoint(sub.replace(ServerHelp.getPortalPublicBaseUrl()+JWT_SLO_PATH));
 | 
			
		||||
        domain.setIdpSsoEndpoint(sub.replace(ContextService.getPortalPublicBaseUrl()+JWT_SSO_PATH));
 | 
			
		||||
        return domain;
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,56 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * eiam-application-jwt - Employee Identity and Access Management
 | 
			
		||||
 * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.application.jwt.model;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * JWT 配置返回
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/5/31 22:46
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "JWT 配置返回响应")
 | 
			
		||||
public class AppJwtGetResult implements Serializable {
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 发起方
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 发起方")
 | 
			
		||||
    private InitLoginType     initLoginType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 登录链接
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 登录链接")
 | 
			
		||||
    private String            initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权范围
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 授权范围")
 | 
			
		||||
    private AuthorizationType authorizationType;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -26,18 +26,16 @@ import cn.topiam.employee.common.enums.app.JwtIdTokenSubjectType;
 | 
			
		|||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.experimental.SuperBuilder;
 | 
			
		||||
import lombok.extern.jackson.Jacksonized;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form 协议配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/02/12 21:43
 | 
			
		||||
 * Created by support@topiam.cn on 2023/02/12 21:43
 | 
			
		||||
 */
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
@SuperBuilder
 | 
			
		||||
@Jacksonized
 | 
			
		||||
public class JwtProtocolConfig extends AbstractProtocolConfig {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +63,7 @@ public class JwtProtocolConfig extends AbstractProtocolConfig {
 | 
			
		|||
    /**
 | 
			
		||||
     * Token 过期时间(秒)
 | 
			
		||||
     */
 | 
			
		||||
    private Integer               idTokenTimeToLive;
 | 
			
		||||
    private String                idTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JWT 公钥
 | 
			
		||||
| 
						 | 
				
			
			@ -81,4 +79,14 @@ public class JwtProtocolConfig extends AbstractProtocolConfig {
 | 
			
		|||
     * id_token 主体类型
 | 
			
		||||
     */
 | 
			
		||||
    private JwtIdTokenSubjectType idTokenSubjectType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登出重定向地址
 | 
			
		||||
     */
 | 
			
		||||
    private String                postLogoutRedirectUri;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否配置
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean               configured;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,21 +19,18 @@ package cn.topiam.employee.application.jwt.pojo;
 | 
			
		|||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.JwtBindingType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.JwtIdTokenSubjectType;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * JWT 配置返回
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/02/12 22:46
 | 
			
		||||
 * Created by support@topiam.cn on 2023/02/12 22:46
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "JWT 配置返回响应")
 | 
			
		||||
| 
						 | 
				
			
			@ -44,24 +41,12 @@ public class AppJwtConfigGetResult implements Serializable {
 | 
			
		|||
    @Schema(description = "应用id")
 | 
			
		||||
    private String                 appId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 发起方
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 发起方")
 | 
			
		||||
    private InitLoginType          initLoginType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 登录链接
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 登录链接")
 | 
			
		||||
    @Schema(description = "SSO 登录链接")
 | 
			
		||||
    private String                 initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权范围
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 授权范围")
 | 
			
		||||
    private AuthorizationType      authorizationType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 业务系统中(或PC程序)的JWT SSO地址,在单点登录时本系统将向该地址用[GET]方式发送id_token信息,参数名为id_token,
 | 
			
		||||
     * 业务系统通过id_token与Public Key可获取业务系统中的用户信息,如果在业务系统(SP)发起登录,请求SP登录地址时如果携带service参数本系统会检验合法性,
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +73,7 @@ public class AppJwtConfigGetResult implements Serializable {
 | 
			
		|||
     * ID_token 有效期
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "Token 过期时间(秒)")
 | 
			
		||||
    private Integer                idTokenTimeToLive;
 | 
			
		||||
    private String                 idTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 协议端点
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,14 +22,13 @@ import java.io.Serializable;
 | 
			
		|||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* 协议端点域
 | 
			
		||||
*
 | 
			
		||||
* @author TopIAM
 | 
			
		||||
* Created by support@topiam.cn on  2023/02/12 23:37
 | 
			
		||||
* Created by support@topiam.cn on 2023/02/12 23:37
 | 
			
		||||
*/
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "协议端点")
 | 
			
		||||
| 
						 | 
				
			
			@ -41,12 +40,6 @@ public class AppJwtProtocolEndpoint implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * IDP SSO 端点
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "IDP SSO 端点")
 | 
			
		||||
    @Schema(description = "IDP SSO 端点")
 | 
			
		||||
    private String            idpSsoEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * IDP SLO 端点
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "IDP SLO 端点")
 | 
			
		||||
    private String            idpSloEndpoint;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,6 @@ package cn.topiam.employee.application.jwt.pojo;
 | 
			
		|||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.JwtBindingType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.JwtIdTokenSubjectType;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +33,7 @@ import jakarta.validation.constraints.NotNull;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/02/12 22:45
 | 
			
		||||
 * Created by support@topiam.cn on 2023/02/12 22:45
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "保存 JWT 应用配置参数")
 | 
			
		||||
| 
						 | 
				
			
			@ -44,11 +43,10 @@ public class AppJwtSaveConfigParam implements Serializable {
 | 
			
		|||
    private static final long     serialVersionUID = 7257798528680745281L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO范围
 | 
			
		||||
     * 登录发起登录URL
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SSO范围不能为空")
 | 
			
		||||
    @Schema(description = "SSO范围")
 | 
			
		||||
    private AuthorizationType     authorizationType;
 | 
			
		||||
    @Schema(description = "登录发起登录URL")
 | 
			
		||||
    private String                initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 业务系统中(或PC程序)的JWT SSO地址,在单点登录时本系统将向该地址用[GET]方式发送id_token信息,参数名为id_token,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam-application</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ import java.util.Optional;
 | 
			
		|||
 | 
			
		||||
import com.nimbusds.jose.jwk.RSAKey;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.AbstractCertificateApplicationService;
 | 
			
		||||
import cn.topiam.employee.application.AbstractCertApplicationService;
 | 
			
		||||
import cn.topiam.employee.application.exception.AppCertNotExistException;
 | 
			
		||||
import cn.topiam.employee.application.exception.AppNotExistException;
 | 
			
		||||
import cn.topiam.employee.application.oidc.model.OidcProtocolConfig;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,24 +40,23 @@ import static cn.topiam.employee.support.util.CertUtils.readPublicKey;
 | 
			
		|||
 * OIDC 应用配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/23 21:58
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/23 21:58
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractOidcCertificateApplicationService extends
 | 
			
		||||
                                                                AbstractCertificateApplicationService
 | 
			
		||||
                                                                implements OidcApplicationService {
 | 
			
		||||
public abstract class AbstractOidcApplicationService extends AbstractCertApplicationService
 | 
			
		||||
                                                     implements OidcApplicationService {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void delete(String appId) {
 | 
			
		||||
        //删除应用
 | 
			
		||||
        appRepository.deleteById(Long.valueOf(appId));
 | 
			
		||||
        appRepository.deleteById(appId);
 | 
			
		||||
        //删除证书
 | 
			
		||||
        appCertRepository.deleteByAppId(Long.valueOf(appId));
 | 
			
		||||
        appCertRepository.deleteByAppId(appId);
 | 
			
		||||
        //删除应用账户
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(Long.valueOf(appId));
 | 
			
		||||
        appAccountRepository.deleteAllByAppId(appId);
 | 
			
		||||
        //删除应用权限策略
 | 
			
		||||
        appAccessPolicyRepository.deleteAllByAppId(Long.valueOf(appId));
 | 
			
		||||
        appAccessPolicyRepository.deleteAllByAppId(appId);
 | 
			
		||||
        //删除OIDC配置
 | 
			
		||||
        appOidcConfigRepository.deleteByAppId(Long.valueOf(appId));
 | 
			
		||||
        appOidcConfigRepository.deleteByAppId(appId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -86,11 +85,12 @@ public abstract class AbstractOidcCertificateApplicationService extends
 | 
			
		|||
 | 
			
		||||
            RSAKey rsaKey = new RSAKey.Builder(rsaPublicKey)
 | 
			
		||||
                    .privateKey(rsaPrivateKey)
 | 
			
		||||
                    .keyID(appCert.getId().toString())
 | 
			
		||||
                    .keyID(appCert.getId())
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            return OidcProtocolConfig.builder()
 | 
			
		||||
                    .appId(appConfig.getAppId().toString())
 | 
			
		||||
                    .appId(appConfig.getAppId())
 | 
			
		||||
                    .appName(appConfig.getAppName())
 | 
			
		||||
                    .clientId(appConfig.getClientId())
 | 
			
		||||
                    .clientSecret(appConfig.getClientSecret())
 | 
			
		||||
                    .appCode(appConfig.getAppCode())
 | 
			
		||||
| 
						 | 
				
			
			@ -105,12 +105,15 @@ public abstract class AbstractOidcCertificateApplicationService extends
 | 
			
		|||
                    .requireProofKey(appConfig.getRequireProofKey())
 | 
			
		||||
                    .tokenEndpointAuthSigningAlgorithm(appConfig.getTokenEndpointAuthSigningAlgorithm())
 | 
			
		||||
                    .refreshTokenTimeToLive(appConfig.getRefreshTokenTimeToLive())
 | 
			
		||||
                    .authorizationCodeTimeToLive(appConfig.getAuthorizationCodeTimeToLive())
 | 
			
		||||
                    .deviceCodeTimeToLive(appConfig.getDeviceCodeTimeToLive())
 | 
			
		||||
                    .idTokenSignatureAlgorithm(appConfig.getIdTokenSignatureAlgorithm())
 | 
			
		||||
                    .idTokenTimeToLive(appConfig.getIdTokenTimeToLive())
 | 
			
		||||
                    .accessTokenFormat(appConfig.getAccessTokenFormat())
 | 
			
		||||
                    .accessTokenTimeToLive(appConfig.getAccessTokenTimeToLive())
 | 
			
		||||
                    .reuseRefreshToken(appConfig.getReuseRefreshToken())
 | 
			
		||||
                    .jwks(Collections.singletonList(rsaKey))
 | 
			
		||||
                    .configured(appConfig.getConfigured())
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            //@formatter:on
 | 
			
		||||
| 
						 | 
				
			
			@ -134,14 +137,14 @@ public abstract class AbstractOidcCertificateApplicationService extends
 | 
			
		|||
     */
 | 
			
		||||
    protected final AppOidcConfigRepository appOidcConfigRepository;
 | 
			
		||||
 | 
			
		||||
    protected AbstractOidcCertificateApplicationService(AppCertRepository appCertRepository,
 | 
			
		||||
                                                        AppAccountRepository appAccountRepository,
 | 
			
		||||
                                                        AppAccessPolicyRepository appAccessPolicyRepository,
 | 
			
		||||
                                                        AppRepository appRepository,
 | 
			
		||||
                                                        AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                                        AppOidcConfigRepository appOidcConfigRepository) {
 | 
			
		||||
        super(appCertRepository, appAccountRepository, appAccessPolicyRepository,
 | 
			
		||||
            appGroupAssociationRepository, appRepository);
 | 
			
		||||
    protected AbstractOidcApplicationService(AppCertRepository appCertRepository,
 | 
			
		||||
                                             AppGroupAssociationRepository appGroupAssociationRepository,
 | 
			
		||||
                                             AppAccountRepository appAccountRepository,
 | 
			
		||||
                                             AppAccessPolicyRepository appAccessPolicyRepository,
 | 
			
		||||
                                             AppRepository appRepository,
 | 
			
		||||
                                             AppOidcConfigRepository appOidcConfigRepository) {
 | 
			
		||||
        super(appCertRepository, appGroupAssociationRepository, appAccountRepository,
 | 
			
		||||
            appAccessPolicyRepository, appRepository);
 | 
			
		||||
        this.appCertRepository = appCertRepository;
 | 
			
		||||
        this.appRepository = appRepository;
 | 
			
		||||
        this.appOidcConfigRepository = appOidcConfigRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ import cn.topiam.employee.application.oidc.model.OidcProtocolConfig;
 | 
			
		|||
 * 应用接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/20 23:20
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/20 23:20
 | 
			
		||||
 */
 | 
			
		||||
public interface OidcApplicationService extends ApplicationService {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
				
			
			@ -17,13 +17,15 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.application.oidc.converter;
 | 
			
		||||
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import org.apache.commons.collections4.CollectionUtils;
 | 
			
		||||
import org.apache.commons.text.StringSubstitutor;
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.mapstruct.Mapping;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.oidc.pojo.AppOidcProtocolEndpoint;
 | 
			
		||||
import cn.topiam.employee.application.oidc.pojo.AppOidcStandardConfigGetResult;
 | 
			
		||||
| 
						 | 
				
			
			@ -31,9 +33,9 @@ import cn.topiam.employee.application.oidc.pojo.AppOidcStandardSaveConfigParam;
 | 
			
		|||
import cn.topiam.employee.common.constant.ProtocolConstants;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppOidcConfigEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.po.AppOidcConfigPO;
 | 
			
		||||
import cn.topiam.employee.core.help.ServerHelp;
 | 
			
		||||
import cn.topiam.employee.core.context.ContextService;
 | 
			
		||||
import cn.topiam.employee.support.util.UrlUtils;
 | 
			
		||||
import static cn.topiam.employee.common.constant.AppConstants.APP_CODE;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.APP_CODE;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.OidcEndpointConstants.OIDC_AUTHORIZE_PATH;
 | 
			
		||||
import static cn.topiam.employee.common.constant.ProtocolConstants.OidcEndpointConstants.WELL_KNOWN_OPENID_CONFIGURATION;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,15 +71,27 @@ public interface AppOidcStandardConfigConverter {
 | 
			
		|||
        //启用PKCE
 | 
			
		||||
        result.setRequireProofKey(config.getRequireProofKey());
 | 
			
		||||
        //访问令牌有效时间
 | 
			
		||||
        result.setAccessTokenTimeToLive(config.getAccessTokenTimeToLive().toString());
 | 
			
		||||
        result.setAccessTokenTimeToLive(
 | 
			
		||||
            String.valueOf(config.getAccessTokenTimeToLive().toMinutes()));
 | 
			
		||||
        //刷新令牌有效时间
 | 
			
		||||
        result.setRefreshTokenTimeToLive(config.getRefreshTokenTimeToLive().toString());
 | 
			
		||||
        result.setRefreshTokenTimeToLive(
 | 
			
		||||
            String.valueOf(config.getRefreshTokenTimeToLive().toMinutes()));
 | 
			
		||||
        //ID令牌有效时间
 | 
			
		||||
        result.setIdTokenTimeToLive(config.getIdTokenTimeToLive().toString());
 | 
			
		||||
        // id 令牌签名算法
 | 
			
		||||
        result.setIdTokenTimeToLive(String.valueOf(config.getIdTokenTimeToLive().toMinutes()));
 | 
			
		||||
        //设备授权码有效期
 | 
			
		||||
        result
 | 
			
		||||
            .setDeviceCodeTimeToLive(String.valueOf(config.getDeviceCodeTimeToLive().toMinutes()));
 | 
			
		||||
        //access_token格式
 | 
			
		||||
        result.setAccessTokenFormat(config.getAccessTokenFormat());
 | 
			
		||||
        //授权码有效期
 | 
			
		||||
        result.setAuthorizationCodeTimeToLive(
 | 
			
		||||
            String.valueOf(config.getAuthorizationCodeTimeToLive().toMinutes()));
 | 
			
		||||
        //ID令牌有效时间
 | 
			
		||||
        result.setReuseRefreshToken(config.getReuseRefreshToken());
 | 
			
		||||
        //ID令牌有效时间
 | 
			
		||||
        result.setIdTokenTimeToLive(String.valueOf(config.getIdTokenTimeToLive().toMinutes()));
 | 
			
		||||
        //ID令牌签名算法
 | 
			
		||||
        result.setIdTokenSignatureAlgorithm(config.getIdTokenSignatureAlgorithm());
 | 
			
		||||
        //SSO 发起方
 | 
			
		||||
        result.setInitLoginType(config.getInitLoginType());
 | 
			
		||||
        //登录发起地址
 | 
			
		||||
        result.setInitLoginUrl(config.getInitLoginUrl());
 | 
			
		||||
        //授权类型
 | 
			
		||||
| 
						 | 
				
			
			@ -91,16 +105,52 @@ public interface AppOidcStandardConfigConverter {
 | 
			
		|||
     * @param config {@link AppOidcConfigEntity}
 | 
			
		||||
     * @return {@link AppOidcConfigEntity}
 | 
			
		||||
     */
 | 
			
		||||
    @Mapping(target = "deleted", ignore = true)
 | 
			
		||||
    @Mapping(target = "responseTypes", ignore = true)
 | 
			
		||||
    @Mapping(target = "updateTime", ignore = true)
 | 
			
		||||
    @Mapping(target = "updateBy", ignore = true)
 | 
			
		||||
    @Mapping(target = "remark", ignore = true)
 | 
			
		||||
    @Mapping(target = "id", ignore = true)
 | 
			
		||||
    @Mapping(target = "createTime", ignore = true)
 | 
			
		||||
    @Mapping(target = "createBy", ignore = true)
 | 
			
		||||
    @Mapping(target = "appId", ignore = true)
 | 
			
		||||
    AppOidcConfigEntity appOidcStandardSaveConfigParamToEntity(AppOidcStandardSaveConfigParam config);
 | 
			
		||||
    default AppOidcConfigEntity appOidcStandardSaveConfigParamToEntity(AppOidcStandardSaveConfigParam config) {
 | 
			
		||||
        if (config == null) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        AppOidcConfigEntity entity = new AppOidcConfigEntity();
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(config.getClientAuthMethods())) {
 | 
			
		||||
            entity.setClientAuthMethods(new LinkedHashSet<>(config.getClientAuthMethods()));
 | 
			
		||||
        }
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(config.getAuthGrantTypes())) {
 | 
			
		||||
            entity.setAuthGrantTypes(new LinkedHashSet<>(config.getAuthGrantTypes()));
 | 
			
		||||
        }
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(config.getRedirectUris())) {
 | 
			
		||||
            entity.setRedirectUris(new LinkedHashSet<>(config.getRedirectUris()));
 | 
			
		||||
        }
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(config.getPostLogoutRedirectUris())) {
 | 
			
		||||
            entity
 | 
			
		||||
                .setPostLogoutRedirectUris(new LinkedHashSet<>(config.getPostLogoutRedirectUris()));
 | 
			
		||||
        }
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(config.getGrantScopes())) {
 | 
			
		||||
            entity.setGrantScopes(new LinkedHashSet<>(config.getGrantScopes()));
 | 
			
		||||
        }
 | 
			
		||||
        entity.setRequireAuthConsent(config.getRequireAuthConsent());
 | 
			
		||||
        entity.setRequireProofKey(config.getRequireProofKey());
 | 
			
		||||
        entity.setTokenEndpointAuthSigningAlgorithm(config.getTokenEndpointAuthSigningAlgorithm());
 | 
			
		||||
        if (config.getRefreshTokenTimeToLive() != null) {
 | 
			
		||||
            entity
 | 
			
		||||
                .setRefreshTokenTimeToLive(Duration.ofMinutes(config.getRefreshTokenTimeToLive()));
 | 
			
		||||
        }
 | 
			
		||||
        if (config.getAuthorizationCodeTimeToLive() != null) {
 | 
			
		||||
            entity.setAuthorizationCodeTimeToLive(
 | 
			
		||||
                Duration.ofMinutes(config.getAuthorizationCodeTimeToLive()));
 | 
			
		||||
        }
 | 
			
		||||
        if (config.getDeviceCodeTimeToLive() != null) {
 | 
			
		||||
            entity.setDeviceCodeTimeToLive(Duration.ofMinutes(config.getDeviceCodeTimeToLive()));
 | 
			
		||||
        }
 | 
			
		||||
        if (config.getIdTokenTimeToLive() != null) {
 | 
			
		||||
            entity.setIdTokenTimeToLive(Duration.ofMinutes(config.getIdTokenTimeToLive()));
 | 
			
		||||
        }
 | 
			
		||||
        if (config.getAccessTokenTimeToLive() != null) {
 | 
			
		||||
            entity.setAccessTokenTimeToLive(Duration.ofMinutes(config.getAccessTokenTimeToLive()));
 | 
			
		||||
        }
 | 
			
		||||
        entity.setIdTokenSignatureAlgorithm(config.getIdTokenSignatureAlgorithm());
 | 
			
		||||
        entity.setAccessTokenFormat(config.getAccessTokenFormat());
 | 
			
		||||
        entity.setReuseRefreshToken(config.getReuseRefreshToken());
 | 
			
		||||
        return entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取协议端点
 | 
			
		||||
| 
						 | 
				
			
			@ -116,21 +166,21 @@ public interface AppOidcStandardConfigConverter {
 | 
			
		|||
        variables.put(APP_CODE,appCode);
 | 
			
		||||
        StringSubstitutor sub = new StringSubstitutor(variables, "{", "}");
 | 
			
		||||
        //Issuer
 | 
			
		||||
        domain.setIssuer(sub.replace(ServerHelp.getPortalPublicBaseUrl()+OIDC_AUTHORIZE_PATH));
 | 
			
		||||
        domain.setIssuer(sub.replace(ContextService.getPortalPublicBaseUrl() + OIDC_AUTHORIZE_PATH));
 | 
			
		||||
        //发现端点
 | 
			
		||||
        domain.setDiscoveryEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() + sub.replace(WELL_KNOWN_OPENID_CONFIGURATION)));
 | 
			
		||||
        domain.setDiscoveryEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() + sub.replace(WELL_KNOWN_OPENID_CONFIGURATION)));
 | 
			
		||||
        //认证端点
 | 
			
		||||
        domain.setAuthorizationEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.AUTHORIZATION_ENDPOINT)));
 | 
			
		||||
        domain.setAuthorizationEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.AUTHORIZATION_ENDPOINT)));
 | 
			
		||||
        //Token端点
 | 
			
		||||
        domain.setTokenEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() + sub.replace( ProtocolConstants.OidcEndpointConstants.TOKEN_ENDPOINT)));
 | 
			
		||||
        domain.setTokenEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() + sub.replace( ProtocolConstants.OidcEndpointConstants.TOKEN_ENDPOINT)));
 | 
			
		||||
        //Jwks端点
 | 
			
		||||
        domain.setJwksEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.JWK_SET_ENDPOINT)));
 | 
			
		||||
        domain.setJwksEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.JWK_SET_ENDPOINT)));
 | 
			
		||||
        //撤销端点
 | 
			
		||||
        domain.setRevokeEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl()+  sub.replace(ProtocolConstants.OidcEndpointConstants.TOKEN_REVOCATION_ENDPOINT)));
 | 
			
		||||
        domain.setRevokeEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl()+  sub.replace(ProtocolConstants.OidcEndpointConstants.TOKEN_REVOCATION_ENDPOINT)));
 | 
			
		||||
        //UserInfo端点
 | 
			
		||||
        domain.setUserinfoEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.OIDC_USER_INFO_ENDPOINT)));
 | 
			
		||||
        domain.setUserinfoEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.OIDC_USER_INFO_ENDPOINT)));
 | 
			
		||||
        //登出端点
 | 
			
		||||
        domain.setEndSessionEndpoint(UrlUtils.format(ServerHelp.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.OIDC_LOGOUT_ENDPOINT)));
 | 
			
		||||
        domain.setEndSessionEndpoint(UrlUtils.format(ContextService.getPortalPublicBaseUrl() +  sub.replace(ProtocolConstants.OidcEndpointConstants.OIDC_LOGOUT_ENDPOINT)));
 | 
			
		||||
        return domain;
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,9 +18,12 @@
 | 
			
		|||
package cn.topiam.employee.application.oidc.model;
 | 
			
		||||
 | 
			
		||||
import java.io.Serial;
 | 
			
		||||
import java.time.Duration;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
import com.nimbusds.jose.jwk.JWK;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.application.AbstractProtocolConfig;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,18 +31,16 @@ import cn.topiam.employee.application.AbstractProtocolConfig;
 | 
			
		|||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.experimental.SuperBuilder;
 | 
			
		||||
import lombok.extern.jackson.Jacksonized;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Oidc 协议配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/8/28 21:43
 | 
			
		||||
 * Created by support@topiam.cn on 2022/8/28 21:43
 | 
			
		||||
 */
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
@SuperBuilder
 | 
			
		||||
@Jacksonized
 | 
			
		||||
public class OidcProtocolConfig extends AbstractProtocolConfig {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
| 
						 | 
				
			
			@ -90,20 +91,30 @@ public class OidcProtocolConfig extends AbstractProtocolConfig {
 | 
			
		|||
     */
 | 
			
		||||
    private String            tokenEndpointAuthSigningAlgorithm;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权码模式授权码生存时间
 | 
			
		||||
     */
 | 
			
		||||
    private Duration          authorizationCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设备模式授权码生存时间
 | 
			
		||||
     */
 | 
			
		||||
    private Duration          deviceCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 刷新 Token生存时间(分钟)
 | 
			
		||||
     */
 | 
			
		||||
    private Integer           refreshTokenTimeToLive;
 | 
			
		||||
    private Duration          refreshTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ID Token生存时间(分钟)
 | 
			
		||||
     */
 | 
			
		||||
    private Integer           idTokenTimeToLive;
 | 
			
		||||
    private Duration          idTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 访问 Token生存时间(分钟)
 | 
			
		||||
     */
 | 
			
		||||
    private Integer           accessTokenTimeToLive;
 | 
			
		||||
    private Duration          accessTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Id Token 签名算法
 | 
			
		||||
| 
						 | 
				
			
			@ -124,4 +135,33 @@ public class OidcProtocolConfig extends AbstractProtocolConfig {
 | 
			
		|||
     * jwks
 | 
			
		||||
     */
 | 
			
		||||
    private List<JWK>         jwks;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否配置
 | 
			
		||||
     */
 | 
			
		||||
    private Boolean           configured;
 | 
			
		||||
 | 
			
		||||
    public Set<String> getRedirectUris() {
 | 
			
		||||
        return CollectionUtils.isEmpty(redirectUris) ? Set.of() : redirectUris;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<String> getPostLogoutRedirectUris() {
 | 
			
		||||
        return CollectionUtils.isEmpty(postLogoutRedirectUris) ? Set.of() : postLogoutRedirectUris;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<String> getGrantScopes() {
 | 
			
		||||
        return CollectionUtils.isEmpty(grantScopes) ? Set.of() : grantScopes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<String> getClientAuthMethods() {
 | 
			
		||||
        return CollectionUtils.isEmpty(clientAuthMethods) ? Set.of() : clientAuthMethods;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Set<String> getResponseTypes() {
 | 
			
		||||
        return CollectionUtils.isEmpty(responseTypes) ? Set.of() : responseTypes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<JWK> getJwks() {
 | 
			
		||||
        return CollectionUtils.isEmpty(jwks) ? List.of() : jwks;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,14 +22,13 @@ import java.io.Serializable;
 | 
			
		|||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 协议端点域
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/6/4 23:37
 | 
			
		||||
 * Created by support@topiam.cn on 2022/6/4 23:37
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "协议端点")
 | 
			
		||||
| 
						 | 
				
			
			@ -40,48 +39,48 @@ public class AppOidcProtocolEndpoint implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * oidcIssuer
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Issuer")
 | 
			
		||||
    @Schema(description = "Issuer")
 | 
			
		||||
    private String            issuer;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * discoveryEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Discovery Endpoint")
 | 
			
		||||
    @Schema(description = "Discovery Endpoint")
 | 
			
		||||
    private String            discoveryEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * UserinfoEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "UserInfo Endpoint")
 | 
			
		||||
    @Schema(description = "UserInfo Endpoint")
 | 
			
		||||
    private String            userinfoEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * jwksEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Jwks Endpoint")
 | 
			
		||||
    @Schema(description = "Jwks Endpoint")
 | 
			
		||||
    private String            jwksEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * revokeEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Revoke Endpoint")
 | 
			
		||||
    @Schema(description = "Revoke Endpoint")
 | 
			
		||||
    private String            revokeEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * tokenEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Token Endpoint")
 | 
			
		||||
    @Schema(description = "Token Endpoint")
 | 
			
		||||
    private String            tokenEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * authorizationEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Authorization Endpoint")
 | 
			
		||||
    @Schema(description = "Authorization Endpoint")
 | 
			
		||||
    private String            authorizationEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * endSessionEndpoint
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "End Session Endpoint")
 | 
			
		||||
    @Schema(description = "End Session Endpoint")
 | 
			
		||||
    private String            endSessionEndpoint;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,18 +22,16 @@ import java.io.Serializable;
 | 
			
		|||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * OIDC 配置返回
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/5/31 22:46
 | 
			
		||||
 * Created by support@topiam.cn on 2022/5/31 22:46
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "OIDC 配置返回响应")
 | 
			
		||||
| 
						 | 
				
			
			@ -42,113 +40,116 @@ public class AppOidcStandardConfigGetResult implements Serializable {
 | 
			
		|||
    @Serial
 | 
			
		||||
    private static final long       serialVersionUID = 4177874005424703372L;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * APP ID
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "appId")
 | 
			
		||||
    private Long                    appId;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 发起方
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 发起方")
 | 
			
		||||
    private InitLoginType           initLoginType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 登录链接
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 登录链接")
 | 
			
		||||
    @Schema(description = "SSO 登录链接")
 | 
			
		||||
    private String                  initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权范围
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "SSO 授权范围")
 | 
			
		||||
    @Schema(description = "SSO 授权范围")
 | 
			
		||||
    private AuthorizationType       authorizationType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * authorizationGrantTypes
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "认证授权类型")
 | 
			
		||||
    @Schema(description = "认证授权类型")
 | 
			
		||||
    private Set<String>             authGrantTypes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 客户端认证方式
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "客户端认证方式")
 | 
			
		||||
    @Schema(description = "客户端认证方式")
 | 
			
		||||
    private Set<String>             clientAuthMethods;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 重定向URI
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "重定向URI")
 | 
			
		||||
    @Schema(description = "重定向URI")
 | 
			
		||||
    private Set<String>             redirectUris;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 登出重定向URI
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "登出重定向URI")
 | 
			
		||||
    @Schema(description = "登出重定向URI")
 | 
			
		||||
    private Set<String>             postLogoutRedirectUris;
 | 
			
		||||
    /**
 | 
			
		||||
     * scopes
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "授权范围")
 | 
			
		||||
    @Schema(description = "授权范围")
 | 
			
		||||
    private Set<String>             grantScopes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 启用PKCE
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "启用PKCE")
 | 
			
		||||
    @Schema(description = "启用PKCE")
 | 
			
		||||
    private Boolean                 requireProofKey;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 令牌 Endpoint 身份验证签名算法
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "令牌 Endpoint 身份验证签名算法")
 | 
			
		||||
    @Schema(description = "令牌 Endpoint 身份验证签名算法")
 | 
			
		||||
    private String                  tokenEndpointAuthSigningAlgorithm;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否需要授权同意
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "是否需要授权同意")
 | 
			
		||||
    @Schema(description = "是否需要授权同意")
 | 
			
		||||
    private Boolean                 requireAuthConsent;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 访问令牌有效时间
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "访问令牌有效时间")
 | 
			
		||||
    @Schema(description = "访问令牌有效时间")
 | 
			
		||||
    private String                  accessTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 刷新令牌有效时间
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "刷新令牌有效时间")
 | 
			
		||||
    @Schema(description = "刷新令牌有效时间")
 | 
			
		||||
    private String                  refreshTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权码 生存时间(分钟)
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "授权码 生存时间(分钟)")
 | 
			
		||||
    private String                  authorizationCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设备CODE 生存时间(分钟)
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "设备CODE 生存时间(分钟)")
 | 
			
		||||
    private String                  deviceCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ID token 有效时间
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "ID 令牌有效时间")
 | 
			
		||||
    @Schema(description = "ID 令牌有效时间")
 | 
			
		||||
    private String                  idTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * id 令牌签名算法
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Id令牌签名算法")
 | 
			
		||||
    @Schema(description = "Id令牌签名算法")
 | 
			
		||||
    private String                  idTokenSignatureAlgorithm;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 协议端点域
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "协议端点域")
 | 
			
		||||
    @Schema(description = "协议端点域")
 | 
			
		||||
    private AppOidcProtocolEndpoint protocolEndpoint;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Access Token 格式
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "Access Token 格式")
 | 
			
		||||
    @Schema(description = "Access Token 格式")
 | 
			
		||||
    private String                  accessTokenFormat;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否重用刷新令牌
 | 
			
		||||
     */
 | 
			
		||||
    @Parameter(description = "是否重用刷新令牌")
 | 
			
		||||
    @Schema(description = "是否重用刷新令牌")
 | 
			
		||||
    private Boolean                 reuseRefreshToken;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,6 @@ import java.util.List;
 | 
			
		|||
 | 
			
		||||
import org.hibernate.validator.constraints.URL;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.common.enums.app.AuthorizationType;
 | 
			
		||||
import cn.topiam.employee.common.enums.app.InitLoginType;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +31,7 @@ import jakarta.validation.constraints.NotNull;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/7/10 01:45
 | 
			
		||||
 * Created by support@topiam.cn on 2022/7/10 01:45
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "保存 OIDC 应用配置参数")
 | 
			
		||||
| 
						 | 
				
			
			@ -64,23 +61,9 @@ public class AppOidcStandardSaveConfigParam implements Serializable {
 | 
			
		|||
    private List<@NotBlank(message = "登出重定向URI不能为空") @URL(message = "登出重定向URI格式不正确") String> postLogoutRedirectUris;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO范围
 | 
			
		||||
     * 登录发起登录URL
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SSO范围不能为空")
 | 
			
		||||
    @Schema(description = "SSO范围")
 | 
			
		||||
    private AuthorizationType                                                                authorizationType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO发起方
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "SSO发起方不能为空")
 | 
			
		||||
    @Schema(description = "SSO发起方")
 | 
			
		||||
    private InitLoginType                                                                    initLoginType;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * SSO 发起登录URL
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "SSO 发起登录URL")
 | 
			
		||||
    @Schema(description = "登录发起登录URL")
 | 
			
		||||
    private String                                                                           initLoginUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -105,9 +88,9 @@ public class AppOidcStandardSaveConfigParam implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * Access Token 生存时间
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "Access Token 生存时间不能为空")
 | 
			
		||||
    @NotNull(message = "Access Token 生存时间不能为空")
 | 
			
		||||
    @Schema(description = "Access Token 生存时间")
 | 
			
		||||
    private String                                                                           accessTokenTimeToLive;
 | 
			
		||||
    private Long                                                                             accessTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Access Token 格式
 | 
			
		||||
| 
						 | 
				
			
			@ -118,16 +101,29 @@ public class AppOidcStandardSaveConfigParam implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * Refresh Token 生存时间
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "Refresh Token 生存时间不能为空")
 | 
			
		||||
    @NotNull(message = "Refresh Token 生存时间不能为空")
 | 
			
		||||
    @Schema(description = "Refresh Token 生存时间")
 | 
			
		||||
    private String                                                                           refreshTokenTimeToLive;
 | 
			
		||||
    private Long                                                                             refreshTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 授权码模式授权码生存时间
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull(message = "授权码模式授权码生存时间不能为空")
 | 
			
		||||
    @Schema(description = "授权码模式授权码生存时间")
 | 
			
		||||
    private Long                                                                             authorizationCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设备模式授权码生存时间
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "设备模式授权码生存时间")
 | 
			
		||||
    private Long                                                                             deviceCodeTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Id Token 生存时间
 | 
			
		||||
     */
 | 
			
		||||
    @NotBlank(message = "Id Token 生存时间不能为空")
 | 
			
		||||
    @NotNull(message = "Id Token 生存时间不能为空")
 | 
			
		||||
    @Schema(description = "Id Token 生存时间")
 | 
			
		||||
    private String                                                                           idTokenTimeToLive;
 | 
			
		||||
    private Long                                                                             idTokenTimeToLive;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * ID Token签名算法
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>pom</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@
 | 
			
		|||
    <parent>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <artifactId>eiam</artifactId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <packaging>jar</packaging>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,74 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * eiam-audit - Employee Identity and Access Management
 | 
			
		||||
 * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.access;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.support.enums.BaseEnum;
 | 
			
		||||
import static cn.topiam.employee.support.constant.EiamConstants.COLON;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 控制台行为审计模块
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/4/24 23:45
 | 
			
		||||
 */
 | 
			
		||||
public interface AuditAccess {
 | 
			
		||||
    String CODE = "audit";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 行为审计
 | 
			
		||||
     */
 | 
			
		||||
    enum Audit implements BaseEnum {
 | 
			
		||||
                                    /**
 | 
			
		||||
                                     * 查看页面
 | 
			
		||||
                                     */
 | 
			
		||||
                                    audit_list("audit_list", "查看页面");
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * CODE
 | 
			
		||||
         */
 | 
			
		||||
        public final static String CODE               = AuditAccess.CODE + COLON + "audit";
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 操作项 CODE 前缀
 | 
			
		||||
         */
 | 
			
		||||
        final static String        ACTION_CODE_PREFIX = CODE + COLON;
 | 
			
		||||
        /**
 | 
			
		||||
         * code
 | 
			
		||||
         */
 | 
			
		||||
        private final String       code;
 | 
			
		||||
        /**
 | 
			
		||||
         * name
 | 
			
		||||
         */
 | 
			
		||||
        private final String       name;
 | 
			
		||||
 | 
			
		||||
        Audit(String code, String name) {
 | 
			
		||||
            this.code = code;
 | 
			
		||||
            this.name = name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String getCode() {
 | 
			
		||||
            return ACTION_CODE_PREFIX + this.code;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public String getDesc() {
 | 
			
		||||
            return this.name;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		|||
 * Audit
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/28 21:56
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/28 21:56
 | 
			
		||||
 */
 | 
			
		||||
@Target({ ElementType.METHOD })
 | 
			
		||||
@Retention(RetentionPolicy.RUNTIME)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ import static cn.topiam.employee.support.constant.EiamConstants.COLON;
 | 
			
		|||
 * 审计切面
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/28 21:20
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/28 21:20
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
@Aspect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import org.springframework.security.core.Authentication;
 | 
			
		|||
 * Audit 解析器
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/28 22:45
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/28 22:45
 | 
			
		||||
 */
 | 
			
		||||
public interface AuditExpressionOperations {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ import lombok.AllArgsConstructor;
 | 
			
		|||
 * AuditExpressionRoot
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/28 22:48
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/28 22:48
 | 
			
		||||
 */
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class AuditExpressionRoot implements AuditExpressionOperations {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,15 +17,13 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.audit.context;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.ttl.TransmittableThreadLocal;
 | 
			
		||||
import com.google.common.collect.Lists;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.entity.Target;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +31,7 @@ import cn.topiam.employee.audit.entity.Target;
 | 
			
		|||
 * AuditContext
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/23 22:39
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/23 22:39
 | 
			
		||||
 */
 | 
			
		||||
public class AuditContext {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -155,7 +153,7 @@ public class AuditContext {
 | 
			
		|||
     */
 | 
			
		||||
    public static void setTarget(Target... target) {
 | 
			
		||||
        if (!Objects.isNull(target)) {
 | 
			
		||||
            TARGET_LIST.set(List.of(target));
 | 
			
		||||
            TARGET_LIST.set(Lists.newArrayList(target));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -168,6 +166,20 @@ public class AuditContext {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add Target
 | 
			
		||||
     */
 | 
			
		||||
    public static void addTarget(Target target) {
 | 
			
		||||
        if (!Objects.isNull(target)) {
 | 
			
		||||
            List<Target> targetList = getTarget();
 | 
			
		||||
            if (Objects.isNull(targetList)) {
 | 
			
		||||
                targetList = new ArrayList<>();
 | 
			
		||||
            }
 | 
			
		||||
            targetList.add(target);
 | 
			
		||||
            TARGET_LIST.set(targetList);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove Content
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.controller;
 | 
			
		||||
package cn.topiam.employee.audit.endpoint;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,11 +26,10 @@ import org.springframework.web.bind.annotation.PathVariable;
 | 
			
		|||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.audit.service.AuditService;
 | 
			
		||||
import cn.topiam.employee.common.constant.AuditConstants;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.Page;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.PageModel;
 | 
			
		||||
import cn.topiam.employee.support.result.ApiRestResult;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,19 +39,25 @@ import lombok.AllArgsConstructor;
 | 
			
		|||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import static cn.topiam.employee.support.constant.EiamConstants.V1_API_PATH;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 系统审计
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/23 21:12
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/23 21:12
 | 
			
		||||
 */
 | 
			
		||||
@Validated
 | 
			
		||||
@Tag(name = "系统审计")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping(value = AuditConstants.AUDIT_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
 | 
			
		||||
@RequestMapping(value = AuditEndpoint.AUDIT_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class AuditController {
 | 
			
		||||
public class AuditEndpoint {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 系统审计API路径
 | 
			
		||||
     */
 | 
			
		||||
    public final static String AUDIT_PATH = V1_API_PATH + "/audit";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 审计列表查询
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.controller.pojo;
 | 
			
		||||
package cn.topiam.employee.audit.endpoint.pojo;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_DATE_TIM
 | 
			
		|||
 * 查询审计日志列表入参
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/23 21:22
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/23 21:22
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "查询审计日志列表入参")
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ public class AuditListQuery implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * 事件状态
 | 
			
		||||
     */
 | 
			
		||||
    @Schema(description = "事件状态")
 | 
			
		||||
    @Parameter(description = "事件状态")
 | 
			
		||||
    private EventStatus     eventStatus;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.controller.pojo;
 | 
			
		||||
package cn.topiam.employee.audit.endpoint.pojo;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_DATE_TIM
 | 
			
		|||
 * 审计日志列表结果
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/24 22:07
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/24 22:07
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "审计日志列表响应")
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@
 | 
			
		|||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.controller.pojo;
 | 
			
		||||
package cn.topiam.employee.audit.endpoint.pojo;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		|||
 * 审计字典结果
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/27 22:35
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/27 22:35
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Schema(description = "字典响应")
 | 
			
		||||
| 
						 | 
				
			
			@ -20,40 +20,40 @@ package cn.topiam.employee.audit.entity;
 | 
			
		|||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserType;
 | 
			
		||||
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NonNull;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Actor
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/5 23:30
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/5 23:30
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
public class Actor implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long serialVersionUID = -1144169992714000310L;
 | 
			
		||||
    public static final String                                       ACTOR_ID         = "actor.id.keyword";
 | 
			
		||||
    public static final String                                       ACTOR_TYPE       = "actor.type.keyword";
 | 
			
		||||
 | 
			
		||||
    public static final String                                       ACTOR_AUTH_TYPE  = "actor.auth_type.keyword";
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long                                        serialVersionUID = -1144169992714000310L;
 | 
			
		||||
    /**
 | 
			
		||||
     * 行动者ID
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private String            id;
 | 
			
		||||
    private String                                                   id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 行动者类型
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private UserType          type;
 | 
			
		||||
    private cn.topiam.employee.support.security.userdetails.UserType type;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 身份验证类型
 | 
			
		||||
     */
 | 
			
		||||
    private String            authType;
 | 
			
		||||
 | 
			
		||||
    private String                                                   authType;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,13 +22,13 @@ import java.time.LocalDateTime;
 | 
			
		|||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hibernate.annotations.JdbcTypeCode;
 | 
			
		||||
import org.hibernate.annotations.SQLDelete;
 | 
			
		||||
import org.hibernate.annotations.Where;
 | 
			
		||||
import org.hibernate.annotations.SoftDelete;
 | 
			
		||||
import org.hibernate.type.SqlTypes;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.enums.EventStatus;
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
import cn.topiam.employee.support.repository.domain.LogicDeleteEntity;
 | 
			
		||||
import cn.topiam.employee.support.repository.SoftDeleteConverter;
 | 
			
		||||
import cn.topiam.employee.support.repository.base.BaseEntity;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserType;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,14 +40,13 @@ import lombok.experimental.Accessors;
 | 
			
		|||
import jakarta.persistence.Column;
 | 
			
		||||
import jakarta.persistence.Entity;
 | 
			
		||||
import jakarta.persistence.Table;
 | 
			
		||||
import static cn.topiam.employee.support.repository.domain.LogicDeleteEntity.SOFT_DELETE_SET;
 | 
			
		||||
import static cn.topiam.employee.support.repository.domain.LogicDeleteEntity.SOFT_DELETE_WHERE;
 | 
			
		||||
import static cn.topiam.employee.support.repository.base.BaseEntity.IS_DELETED_COLUMN;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 审计
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/8/1 21:41
 | 
			
		||||
 * Created by support@topiam.cn on 2021/8/1 21:41
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
| 
						 | 
				
			
			@ -55,10 +54,9 @@ import static cn.topiam.employee.support.repository.domain.LogicDeleteEntity.SOF
 | 
			
		|||
@RequiredArgsConstructor
 | 
			
		||||
@Accessors(chain = true)
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "audit")
 | 
			
		||||
@SQLDelete(sql = "update audit set " + SOFT_DELETE_SET + " where id_ = ?")
 | 
			
		||||
@Where(clause = SOFT_DELETE_WHERE)
 | 
			
		||||
public class AuditEntity extends LogicDeleteEntity<Long> {
 | 
			
		||||
@Table(name = "eiam_audit")
 | 
			
		||||
@SoftDelete(columnName = IS_DELETED_COLUMN, converter = SoftDeleteConverter.class)
 | 
			
		||||
public class AuditEntity extends BaseEntity {
 | 
			
		||||
 | 
			
		||||
    @Serial
 | 
			
		||||
    private static final long  serialVersionUID      = -3119319193111206582L;
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +66,6 @@ public class AuditEntity extends LogicDeleteEntity<Long> {
 | 
			
		|||
    public static final String ACTOR_ID_FIELD_NAME   = "actorId";
 | 
			
		||||
 | 
			
		||||
    public static final String EVENT_TIME_FIELD_NAME = "eventTime";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Request Id
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,6 @@ import java.io.Serial;
 | 
			
		|||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
 | 
			
		||||
import org.springframework.data.elasticsearch.annotations.Field;
 | 
			
		||||
import org.springframework.data.elasticsearch.annotations.FieldType;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.enums.EventStatus;
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +31,7 @@ import lombok.Data;
 | 
			
		|||
 * Event
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/5 23:33
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/5 23:33
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +40,7 @@ public class Event implements Serializable {
 | 
			
		|||
    @Serial
 | 
			
		||||
    private static final long  serialVersionUID = -1144169992714000310L;
 | 
			
		||||
 | 
			
		||||
    public static final String EVENT_TYPE       = "event.type";
 | 
			
		||||
    public static final String EVENT_TYPE       = "event.type.keyword";
 | 
			
		||||
 | 
			
		||||
    public static final String EVENT_TIME       = "event.time";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -53,37 +49,31 @@ public class Event implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * 审计事件类型
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Keyword, name = "type")
 | 
			
		||||
    private EventType          type;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 参数
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Text, name = "param")
 | 
			
		||||
    private String             param;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 事件内容
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Text, name = "content")
 | 
			
		||||
    private String             content;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 事件结果
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Text, name = "result")
 | 
			
		||||
    private String             result;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 事件时间
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Date, name = "time", format = DateFormat.date_hour_minute_second_millis)
 | 
			
		||||
    private LocalDateTime      time;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 事件状态
 | 
			
		||||
     */
 | 
			
		||||
    @Field(type = FieldType.Keyword, name = "status")
 | 
			
		||||
    private EventStatus        status;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,8 +20,6 @@ package cn.topiam.employee.audit.entity;
 | 
			
		|||
import java.io.Serial;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.support.geo.GeoLocationProvider;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
| 
						 | 
				
			
			@ -33,7 +31,7 @@ import lombok.NoArgsConstructor;
 | 
			
		|||
 * 地理位置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/5 23:31
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/5 23:31
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,65 @@
 | 
			
		|||
/*
 | 
			
		||||
 * eiam-audit - Employee Identity and Access Management
 | 
			
		||||
 * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit.entity;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * GeoPoint
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on 2024/04/17 23:30
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public class GeoPoint {
 | 
			
		||||
 | 
			
		||||
    private double lat;
 | 
			
		||||
    private double lon;
 | 
			
		||||
 | 
			
		||||
    private GeoPoint() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public GeoPoint(double latitude, double longitude) {
 | 
			
		||||
        this.lat = latitude;
 | 
			
		||||
        this.lon = longitude;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o) {
 | 
			
		||||
        if (this == o) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (o == null || getClass() != o.getClass()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        GeoPoint geoPoint = (GeoPoint) o;
 | 
			
		||||
        return Double.compare(geoPoint.lat, lat) == 0 && Double.compare(geoPoint.lon, lon) == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        return Objects.hash(lat, lon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "GeoPoint{" + "lat=" + lat + ", lon=" + lon + '}';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,16 +22,13 @@ import java.io.Serializable;
 | 
			
		|||
 | 
			
		||||
import cn.topiam.employee.audit.enums.TargetType;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import lombok.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Target
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/5 23:34
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/5 23:34
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
| 
						 | 
				
			
			@ -47,20 +44,27 @@ public class Target implements Serializable {
 | 
			
		|||
    /**
 | 
			
		||||
     * 目标 ID
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private String             id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 目标名称
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private String             name;
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * 目标类型
 | 
			
		||||
     */
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private TargetType         type;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 目标类型名称
 | 
			
		||||
     */
 | 
			
		||||
    private String             typeName;
 | 
			
		||||
 | 
			
		||||
    public String getTypeName() {
 | 
			
		||||
        return type.getDesc();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import lombok.NoArgsConstructor;
 | 
			
		|||
/**
 | 
			
		||||
 * UserAgent
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/5 23:31
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/5 23:31
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@Builder
 | 
			
		||||
| 
						 | 
				
			
			@ -35,15 +35,17 @@ import lombok.NoArgsConstructor;
 | 
			
		|||
@NoArgsConstructor
 | 
			
		||||
public class UserAgent implements Serializable {
 | 
			
		||||
 | 
			
		||||
    private String deviceType;
 | 
			
		||||
    public static final String USER_AGENT_BROWSER = "user_agent.browser.keyword";
 | 
			
		||||
 | 
			
		||||
    private String platform;
 | 
			
		||||
    private String             deviceType;
 | 
			
		||||
 | 
			
		||||
    private String platformVersion;
 | 
			
		||||
    private String             platform;
 | 
			
		||||
 | 
			
		||||
    private String browser;
 | 
			
		||||
    private String             platformVersion;
 | 
			
		||||
 | 
			
		||||
    private String browserType;
 | 
			
		||||
    private String             browser;
 | 
			
		||||
 | 
			
		||||
    private String browserMajorVersion;
 | 
			
		||||
    private String             browserType;
 | 
			
		||||
 | 
			
		||||
    private String             browserMajorVersion;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import lombok.Getter;
 | 
			
		|||
 * 事件状态
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/11/6 21:57
 | 
			
		||||
 * Created by support@topiam.cn on 2022/11/6 21:57
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public enum EventStatus {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ package cn.topiam.employee.audit.enums;
 | 
			
		|||
import com.fasterxml.jackson.annotation.JsonValue;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
import cn.topiam.employee.support.exception.BadParamsException;
 | 
			
		||||
import cn.topiam.employee.support.web.converter.EnumConvert;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +29,7 @@ import lombok.Getter;
 | 
			
		|||
 * 目标类型
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/10/27 23:46
 | 
			
		||||
 * Created by support@topiam.cn on 2022/10/27 23:46
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public enum TargetType {
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +127,11 @@ public enum TargetType {
 | 
			
		|||
                        /**
 | 
			
		||||
                         * 门户端
 | 
			
		||||
                         */
 | 
			
		||||
                        PORTAL("portal", "门户端");
 | 
			
		||||
                        PORTAL("portal", "门户端"),
 | 
			
		||||
                        /**
 | 
			
		||||
                         * 用户绑定三方用户
 | 
			
		||||
                         */
 | 
			
		||||
                        USER_IDP("user_idp", "用户绑定三方用户");
 | 
			
		||||
 | 
			
		||||
    @JsonValue
 | 
			
		||||
    private final String code;
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +156,7 @@ public enum TargetType {
 | 
			
		|||
                return status;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
        throw new BadParamsException("无效的目标类型");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ import jakarta.persistence.Converter;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/10 23:02
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/10 23:02
 | 
			
		||||
 */
 | 
			
		||||
@Converter(autoApply = true)
 | 
			
		||||
public class AuditTypeConverter implements AttributeConverter<EventType, String> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ import jakarta.persistence.Converter;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/10 23:02
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/10 23:02
 | 
			
		||||
 */
 | 
			
		||||
@Converter(autoApply = true)
 | 
			
		||||
public class EventStatusConverter implements AttributeConverter<EventStatus, String> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ import jakarta.persistence.Converter;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/10 23:02
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/10 23:02
 | 
			
		||||
 */
 | 
			
		||||
@Converter(autoApply = true)
 | 
			
		||||
public class TargetTypeConverter implements AttributeConverter<TargetType, String> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ import lombok.Getter;
 | 
			
		|||
 * 审计事件
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/8/1 21:56
 | 
			
		||||
 * Created by support@topiam.cn on 2021/8/1 21:56
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public class AuditEvent extends ApplicationEvent {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ import cn.topiam.employee.audit.repository.AuditRepository;
 | 
			
		|||
 * 事件监听
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/12 22:49
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/12 22:49
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
@Async
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,6 @@ import java.util.Objects;
 | 
			
		|||
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.springframework.context.ApplicationEventPublisher;
 | 
			
		||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
 | 
			
		||||
import org.springframework.security.core.Authentication;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContext;
 | 
			
		||||
import org.springframework.security.core.context.SecurityContextHolder;
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +35,7 @@ import com.google.common.collect.Maps;
 | 
			
		|||
import cn.topiam.employee.audit.entity.*;
 | 
			
		||||
import cn.topiam.employee.audit.enums.EventStatus;
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
import cn.topiam.employee.support.context.ServletContextHelp;
 | 
			
		||||
import cn.topiam.employee.support.context.ServletContextService;
 | 
			
		||||
import cn.topiam.employee.support.geo.GeoLocationService;
 | 
			
		||||
import cn.topiam.employee.support.security.authentication.WebAuthenticationDetails;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserDetails;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +51,7 @@ import static cn.topiam.employee.support.util.StringUtils.replaceBlank;
 | 
			
		|||
 * 发布审计事件
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/8/1 21:04
 | 
			
		||||
 * Created by support@topiam.cn on 2021/8/1 21:04
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class AuditEventPublish {
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +76,7 @@ public class AuditEventPublish {
 | 
			
		|||
        //封装操作人
 | 
			
		||||
        Actor actor = getActor();
 | 
			
		||||
        //Publish AuditEvent
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextHelp.getSession().getId(), actor, event, userAgent, geoLocationModal, null));
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextService.getSession().getId(), actor, event, userAgent, geoLocationModal, null));
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +107,7 @@ public class AuditEventPublish {
 | 
			
		|||
        //封装操作人
 | 
			
		||||
        Actor actor = getActor(authentication);
 | 
			
		||||
        //Publish AuditEvent
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextHelp.getSession().getId(), actor, event, userAgent, geoLocationModal, targets));
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextService.getSession().getId(), actor, event, userAgent, geoLocationModal, targets));
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -130,7 +129,7 @@ public class AuditEventPublish {
 | 
			
		|||
        //封装用户代理
 | 
			
		||||
        UserAgent userAgent = getUserAgent();
 | 
			
		||||
        //Publish AuditEvent
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextHelp.getSession().getId(), actor, event, userAgent, geoLocationModal, null));
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextService.getSession().getId(), actor, event, userAgent, geoLocationModal, null));
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +170,7 @@ public class AuditEventPublish {
 | 
			
		|||
            actor = getActor();
 | 
			
		||||
        }
 | 
			
		||||
        //Publish AuditEvent
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextHelp.getSession().getId(), actor, event, userAgent, geoLocationModal, target));
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextService.getSession().getId(), actor, event, userAgent, geoLocationModal, target));
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -197,7 +196,7 @@ public class AuditEventPublish {
 | 
			
		|||
        //封装操作人
 | 
			
		||||
        Actor actor = getActor();
 | 
			
		||||
        //Publish AuditEvent
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextHelp.getSession().getId(), actor, event, userAgent, geoLocationModal, target));
 | 
			
		||||
        applicationEventPublisher.publishEvent(new AuditEvent(TraceUtils.get(), ServletContextService.getSession().getId(), actor, event, userAgent, geoLocationModal, target));
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -272,7 +271,7 @@ public class AuditEventPublish {
 | 
			
		|||
     */
 | 
			
		||||
    private UserAgent getUserAgent() {
 | 
			
		||||
        //@formatter:off
 | 
			
		||||
        HttpServletRequest request = ServletContextHelp.getRequest();
 | 
			
		||||
        HttpServletRequest request = ServletContextService.getRequest();
 | 
			
		||||
        cn.topiam.employee.support.web.useragent.UserAgent ua = UserAgentParser.getUserAgent(request);
 | 
			
		||||
        return UserAgent.builder()
 | 
			
		||||
                .browser(ua.getBrowser())
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +291,7 @@ public class AuditEventPublish {
 | 
			
		|||
     */
 | 
			
		||||
    private GeoLocation getGeoLocation() {
 | 
			
		||||
        //@formatter:off
 | 
			
		||||
        HttpServletRequest request = ServletContextHelp.getRequest();
 | 
			
		||||
        HttpServletRequest request = ServletContextService.getRequest();
 | 
			
		||||
        String ip = IpUtils.getIpAddr(request);
 | 
			
		||||
        cn.topiam.employee.support.geo.GeoLocation geoLocation = geoLocationService.getGeoLocation(ip);
 | 
			
		||||
        if (Objects.isNull(geoLocation)){
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ import lombok.EqualsAndHashCode;
 | 
			
		|||
 * 审计资源
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/29 21:07
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/29 21:07
 | 
			
		||||
 */
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ import lombok.EqualsAndHashCode;
 | 
			
		|||
 * 审计资源
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/29 21:07
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/29 21:07
 | 
			
		||||
 */
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ import lombok.Data;
 | 
			
		|||
 * 类型
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 23:06
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 23:06
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import static cn.topiam.employee.support.security.userdetails.UserType.ADMIN;
 | 
			
		|||
 * 账户资源
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 22:58
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 22:58
 | 
			
		||||
 */
 | 
			
		||||
public class AccountEventType {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ import static cn.topiam.employee.audit.event.ConsoleResource.APP_RESOURCE;
 | 
			
		|||
 * 应用资源
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 23:00
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 23:00
 | 
			
		||||
 */
 | 
			
		||||
public class AppEventType {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +69,18 @@ public class AppEventType {
 | 
			
		|||
    public static Type APP_ACCESS_POLICY               = new Type("eiam:event:app:access_policy",
 | 
			
		||||
        "添加应用访问授权", APP_RESOURCE, List.of(UserType.ADMIN));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 启用应用访问授权
 | 
			
		||||
     */
 | 
			
		||||
    public static Type ENABLE_APP_ACCESS_POLICY        = new Type(
 | 
			
		||||
        "eiam:event:app:enable_access_policy", "启用应用访问授权", APP_RESOURCE, List.of(UserType.ADMIN));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 禁用应用访问授权
 | 
			
		||||
     */
 | 
			
		||||
    public static Type DISABLE_APP_ACCESS_POLICY       = new Type(
 | 
			
		||||
        "eiam:event:app:disable_access_policy", "禁用应用访问授权", APP_RESOURCE, List.of(UserType.ADMIN));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除访问授权
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +93,12 @@ public class AppEventType {
 | 
			
		|||
    public static Type ADD_APP_ACCOUNT                 = new Type("eiam:event:app:add_app_account",
 | 
			
		||||
        "添加应用账户", APP_RESOURCE, List.of(UserType.ADMIN));
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新默认应用账户
 | 
			
		||||
     */
 | 
			
		||||
    public static Type UPDATE_DEFAULT_APP_ACCOUNT      = new Type(
 | 
			
		||||
        "eiam:event:app:update_default_app_account", "更新默认应用账户", APP_RESOURCE,
 | 
			
		||||
        List.of(UserType.ADMIN));
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除应用账户
 | 
			
		||||
     */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,13 +22,13 @@ import java.util.List;
 | 
			
		|||
import cn.topiam.employee.audit.event.ConsoleResource;
 | 
			
		||||
import cn.topiam.employee.audit.event.Type;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserType;
 | 
			
		||||
import static cn.topiam.employee.audit.event.ConsoleResource.*;
 | 
			
		||||
import static cn.topiam.employee.audit.event.ConsoleResource.IDP_RESOURCE;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 认证资源
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 22:59
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 22:59
 | 
			
		||||
 */
 | 
			
		||||
public class AuthenticationEventType {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ import lombok.Getter;
 | 
			
		|||
 * 事件类型
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/29 21:00
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/29 21:00
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
public enum EventType {
 | 
			
		||||
| 
						 | 
				
			
			@ -304,6 +304,15 @@ public enum EventType {
 | 
			
		|||
                        * 应用授权
 | 
			
		||||
                        */
 | 
			
		||||
                       APP_AUTHORIZATION(AppEventType.APP_ACCESS_POLICY),
 | 
			
		||||
                       /**
 | 
			
		||||
                        * 启用应用访问授权
 | 
			
		||||
                        */
 | 
			
		||||
                       ENABLE_APP_ACCESS_POLICY(AppEventType.ENABLE_APP_ACCESS_POLICY),
 | 
			
		||||
 | 
			
		||||
                       /**
 | 
			
		||||
                        * 禁用应用访问授权
 | 
			
		||||
                        */
 | 
			
		||||
                       DISABLE_APP_ACCESS_POLICY(AppEventType.DISABLE_APP_ACCESS_POLICY),
 | 
			
		||||
                       /**
 | 
			
		||||
                        * 删除应用授权
 | 
			
		||||
                        */
 | 
			
		||||
| 
						 | 
				
			
			@ -312,6 +321,10 @@ public enum EventType {
 | 
			
		|||
                        * 添加应用账户
 | 
			
		||||
                        */
 | 
			
		||||
                       ADD_APP_ACCOUNT(AppEventType.ADD_APP_ACCOUNT),
 | 
			
		||||
                       /**
 | 
			
		||||
                        * 更新默认应用账户
 | 
			
		||||
                        */
 | 
			
		||||
                       UPDATE_DEFAULT_APP_ACCOUNT(AppEventType.UPDATE_DEFAULT_APP_ACCOUNT),
 | 
			
		||||
                       /**
 | 
			
		||||
                        * 删除应用账户
 | 
			
		||||
                        */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import static cn.topiam.employee.audit.event.ConsoleResource.SESSION_RESOURCE;
 | 
			
		|||
 * 系统监控
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 22:58
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 22:58
 | 
			
		||||
 */
 | 
			
		||||
public class MonitorEventType {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,13 +22,14 @@ import java.util.List;
 | 
			
		|||
import cn.topiam.employee.audit.event.ConsoleResource;
 | 
			
		||||
import cn.topiam.employee.audit.event.Type;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserType;
 | 
			
		||||
import static cn.topiam.employee.audit.event.PortalResource.*;
 | 
			
		||||
import static cn.topiam.employee.audit.event.PortalResource.MY_ACCOUNT_RESOURCE;
 | 
			
		||||
import static cn.topiam.employee.audit.event.PortalResource.MY_APP_RESOURCE;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 门户端审计事件类型
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 22:58
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 22:58
 | 
			
		||||
 */
 | 
			
		||||
public class PortalEventType {
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import static cn.topiam.employee.audit.event.ConsoleResource.*;
 | 
			
		|||
 * 系统设置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/11/24 22:58
 | 
			
		||||
 * Created by support@topiam.cn on 2021/11/24 22:58
 | 
			
		||||
 */
 | 
			
		||||
public class SettingEventType {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,6 @@
 | 
			
		|||
 * 审计事件
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/11 22:10
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/11 22:10
 | 
			
		||||
 */
 | 
			
		||||
package cn.topiam.employee.audit;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,19 +28,19 @@ import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
 | 
			
		|||
 * 组织成员
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/10/2 02:53
 | 
			
		||||
 * Created by support@topiam.cn on 2022/10/2 02:53
 | 
			
		||||
 */
 | 
			
		||||
public interface AuditCustomizedRepository {
 | 
			
		||||
 | 
			
		||||
    List<AuditStatisticsResult> authnHotProvider(EventType type, LocalDateTime startTime,
 | 
			
		||||
    List<AuditStatisticsResult> authnHotProvider(List<EventType> types, LocalDateTime startTime,
 | 
			
		||||
                                                 LocalDateTime endTime);
 | 
			
		||||
 | 
			
		||||
    List<AuthnQuantityResult> authnQuantity(EventType type, LocalDateTime startTime,
 | 
			
		||||
    List<AuthnQuantityResult> authnQuantity(List<EventType> types, LocalDateTime startTime,
 | 
			
		||||
                                            LocalDateTime endTime, String dateFormat);
 | 
			
		||||
 | 
			
		||||
    List<AuditStatisticsResult> appVisitRank(EventType type, LocalDateTime startTime,
 | 
			
		||||
                                             LocalDateTime endTime);
 | 
			
		||||
 | 
			
		||||
    List<AuditStatisticsResult> authnZone(EventType type, LocalDateTime startTime,
 | 
			
		||||
    List<AuditStatisticsResult> authnZone(List<EventType> types, LocalDateTime startTime,
 | 
			
		||||
                                          LocalDateTime endTime);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,48 +18,28 @@
 | 
			
		|||
package cn.topiam.employee.audit.repository;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.entity.AuditEntity;
 | 
			
		||||
import cn.topiam.employee.support.repository.LogicDeleteRepository;
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 行为审计repository
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/11 22:32
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/11 22:32
 | 
			
		||||
 */
 | 
			
		||||
@Repository
 | 
			
		||||
public interface AuditRepository extends LogicDeleteRepository<AuditEntity, Long>,
 | 
			
		||||
public interface AuditRepository extends JpaRepository<AuditEntity, String>,
 | 
			
		||||
                                 AuditCustomizedRepository, JpaSpecificationExecutor<AuditEntity> {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 统计指定时间范围内用户登录失败次数
 | 
			
		||||
     *
 | 
			
		||||
     * @param startTime {@link LocalDateTime}
 | 
			
		||||
     * @param endTime {@link LocalDateTime}
 | 
			
		||||
     * @param userId {@link Long}
 | 
			
		||||
     * @return {@link Integer}
 | 
			
		||||
     */
 | 
			
		||||
    @Query(value = "SELECT count(*) FROM `audit` WHERE event_time BETWEEN :startTime AND :endTime AND actor_id  = :userId AND event_type = 'eiam:event:login:portal' AND event_status = 'fail'", nativeQuery = true)
 | 
			
		||||
    Integer countLoginFailByUserId(@Param("startTime") LocalDateTime startTime,
 | 
			
		||||
                                   @Param("endTime") LocalDateTime endTime,
 | 
			
		||||
                                   @Param("userId") Long userId);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据requestId查询审计是否已存在
 | 
			
		||||
     *
 | 
			
		||||
     * @param requestId {@link String}
 | 
			
		||||
     * @return {@link AuditEntity}
 | 
			
		||||
     */
 | 
			
		||||
    Optional<AuditEntity> findByRequestId(String requestId);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT COUNT(*) FROM audit WHERE event_type = :type AND event_time BETWEEN :startTime AND :endTime", nativeQuery = true)
 | 
			
		||||
    Long countByTypeAndTime(@Param("type") String type, @Param("startTime") LocalDateTime startTime,
 | 
			
		||||
    @Query(value = "SELECT COUNT(*) FROM AuditEntity WHERE eventType = :type AND eventTime BETWEEN :startTime AND :endTime")
 | 
			
		||||
    Long countByTypeAndTime(@Param("type") EventType type,
 | 
			
		||||
                            @Param("startTime") LocalDateTime startTime,
 | 
			
		||||
                            @Param("endTime") LocalDateTime endTime);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,8 +19,10 @@ package cn.topiam.employee.audit.repository.impl;
 | 
			
		|||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.springframework.jdbc.core.JdbcTemplate;
 | 
			
		||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 | 
			
		||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
| 
						 | 
				
			
			@ -35,58 +37,69 @@ import lombok.RequiredArgsConstructor;
 | 
			
		|||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2022/10/2 02:54
 | 
			
		||||
 * Created by support@topiam.cn on 2022/10/2 02:54
 | 
			
		||||
 */
 | 
			
		||||
@Repository
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
public class AuditCustomizedRepositoryImpl implements AuditCustomizedRepository {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JdbcTemplate
 | 
			
		||||
     * NamedParameterJdbcTemplate
 | 
			
		||||
     */
 | 
			
		||||
    private final JdbcTemplate jdbcTemplate;
 | 
			
		||||
    private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<AuditStatisticsResult> authnHotProvider(EventType type, LocalDateTime startTime,
 | 
			
		||||
    public List<AuditStatisticsResult> authnHotProvider(List<EventType> types,
 | 
			
		||||
                                                        LocalDateTime startTime,
 | 
			
		||||
                                                        LocalDateTime endTime) {
 | 
			
		||||
        String sql = """
 | 
			
		||||
                        SELECT
 | 
			
		||||
                            actor_auth_type AS key_,
 | 
			
		||||
                            COUNT(*) AS count_
 | 
			
		||||
                        FROM
 | 
			
		||||
                            audit
 | 
			
		||||
                            eiam_audit
 | 
			
		||||
                        WHERE
 | 
			
		||||
                            event_type = ?
 | 
			
		||||
                            AND event_time BETWEEN ?
 | 
			
		||||
                            AND ?
 | 
			
		||||
                            event_type IN (:types)
 | 
			
		||||
                            AND event_time BETWEEN :startTime
 | 
			
		||||
                            AND :endTime
 | 
			
		||||
                        GROUP BY
 | 
			
		||||
                            actor_auth_type
 | 
			
		||||
                        ORDER BY count_
 | 
			
		||||
                """;
 | 
			
		||||
        return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
 | 
			
		||||
            endTime);
 | 
			
		||||
        MapSqlParameterSource params = new MapSqlParameterSource();
 | 
			
		||||
        params.addValue("types",
 | 
			
		||||
            types.stream().map(EventType::getCode).collect(Collectors.toList()));
 | 
			
		||||
        params.addValue("startTime", startTime);
 | 
			
		||||
        params.addValue("endTime", endTime);
 | 
			
		||||
        return namedParameterJdbcTemplate.query(sql, params, new AuditStatisticsResultMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<AuthnQuantityResult> authnQuantity(EventType type, LocalDateTime startTime,
 | 
			
		||||
    public List<AuthnQuantityResult> authnQuantity(List<EventType> types, LocalDateTime startTime,
 | 
			
		||||
                                                   LocalDateTime endTime, String dateFormat) {
 | 
			
		||||
        String sql = """
 | 
			
		||||
                        SELECT
 | 
			
		||||
                            DATE_FORMAT( event_time, ? ) AS name_,
 | 
			
		||||
                            DATE_FORMAT( event_time, :dateFormat ) AS name_,
 | 
			
		||||
                            COUNT(*) AS count_,
 | 
			
		||||
                            event_status AS status_
 | 
			
		||||
                         FROM
 | 
			
		||||
                            audit
 | 
			
		||||
                            eiam_audit
 | 
			
		||||
                         WHERE
 | 
			
		||||
                            event_type = ?
 | 
			
		||||
                            AND event_time BETWEEN ?
 | 
			
		||||
                            AND ?
 | 
			
		||||
                            event_type IN (:types)
 | 
			
		||||
                            AND event_time BETWEEN :startTime
 | 
			
		||||
                            AND :endTime
 | 
			
		||||
                         GROUP BY
 | 
			
		||||
                            DATE_FORMAT( event_time, ? ),
 | 
			
		||||
                            DATE_FORMAT( event_time, :dateFormat ),
 | 
			
		||||
                            event_status
 | 
			
		||||
                        ORDER BY name_
 | 
			
		||||
                """;
 | 
			
		||||
 | 
			
		||||
        return jdbcTemplate.query(sql, new AuthnQuantityResultMapper(), dateFormat, type.getCode(),
 | 
			
		||||
            startTime, endTime, dateFormat);
 | 
			
		||||
        MapSqlParameterSource params = new MapSqlParameterSource();
 | 
			
		||||
        params.addValue("types",
 | 
			
		||||
            types.stream().map(EventType::getCode).collect(Collectors.toList()));
 | 
			
		||||
        params.addValue("startTime", startTime);
 | 
			
		||||
        params.addValue("endTime", endTime);
 | 
			
		||||
        params.addValue("dateFormat", dateFormat);
 | 
			
		||||
        return namedParameterJdbcTemplate.query(sql, params, new AuthnQuantityResultMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
| 
						 | 
				
			
			@ -97,41 +110,49 @@ public class AuditCustomizedRepositoryImpl implements AuditCustomizedRepository
 | 
			
		|||
                            JSON_EXTRACT( target_, '$[0].id' ) AS key_,
 | 
			
		||||
                            COUNT(*) AS count_
 | 
			
		||||
                         FROM
 | 
			
		||||
                            audit
 | 
			
		||||
                            eiam_audit
 | 
			
		||||
                         WHERE
 | 
			
		||||
                            event_type = ?
 | 
			
		||||
                            AND event_time BETWEEN ?
 | 
			
		||||
                            AND ?
 | 
			
		||||
                            event_type = :type
 | 
			
		||||
                            AND event_time BETWEEN :startTime
 | 
			
		||||
                            AND :endTime
 | 
			
		||||
                         GROUP BY
 | 
			
		||||
                            JSON_EXTRACT(
 | 
			
		||||
                                target_,
 | 
			
		||||
                            '$[0].id'
 | 
			
		||||
                            )
 | 
			
		||||
                        ORDER BY count_
 | 
			
		||||
                """;
 | 
			
		||||
        return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
 | 
			
		||||
            endTime);
 | 
			
		||||
        MapSqlParameterSource params = new MapSqlParameterSource();
 | 
			
		||||
        params.addValue("type", type.getCode());
 | 
			
		||||
        params.addValue("startTime", startTime);
 | 
			
		||||
        params.addValue("endTime", endTime);
 | 
			
		||||
        return namedParameterJdbcTemplate.query(sql, params, new AuditStatisticsResultMapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<AuditStatisticsResult> authnZone(EventType type, LocalDateTime startTime,
 | 
			
		||||
    public List<AuditStatisticsResult> authnZone(List<EventType> types, LocalDateTime startTime,
 | 
			
		||||
                                                 LocalDateTime endTime) {
 | 
			
		||||
        String sql = """
 | 
			
		||||
                        SELECT
 | 
			
		||||
                            JSON_EXTRACT( target_, '$.provinceCode' ) AS key_,
 | 
			
		||||
                            JSON_EXTRACT( geo_location, '$.provinceCode' ) AS key_,
 | 
			
		||||
                            COUNT(*) AS count_
 | 
			
		||||
                         FROM
 | 
			
		||||
                            audit
 | 
			
		||||
                            eiam_audit
 | 
			
		||||
                         WHERE
 | 
			
		||||
                            event_type = ?
 | 
			
		||||
                            AND event_time BETWEEN ?
 | 
			
		||||
                            AND ?
 | 
			
		||||
                            event_type IN (:types)
 | 
			
		||||
                            AND event_time BETWEEN :startTime
 | 
			
		||||
                            AND :endTime
 | 
			
		||||
                         GROUP BY
 | 
			
		||||
                         	JSON_EXTRACT(
 | 
			
		||||
                         		target_,
 | 
			
		||||
                         	geo_location,
 | 
			
		||||
                         	'$.provinceCode'
 | 
			
		||||
                         	)
 | 
			
		||||
                """;
 | 
			
		||||
        return jdbcTemplate.query(sql, new AuditStatisticsResultMapper(), type.getCode(), startTime,
 | 
			
		||||
            endTime);
 | 
			
		||||
        MapSqlParameterSource params = new MapSqlParameterSource();
 | 
			
		||||
        params.addValue("types",
 | 
			
		||||
            types.stream().map(EventType::getCode).collect(Collectors.toList()));
 | 
			
		||||
        params.addValue("startTime", startTime);
 | 
			
		||||
        params.addValue("endTime", endTime);
 | 
			
		||||
        return namedParameterJdbcTemplate.query(sql, params, new AuditStatisticsResultMapper());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ import cn.topiam.employee.audit.repository.result.AuditStatisticsResult;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/10/04 22:25
 | 
			
		||||
 * Created by support@topiam.cn on 2023/10/04 22:25
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("DuplicatedCode")
 | 
			
		||||
public class AuditStatisticsResultMapper implements RowMapper<AuditStatisticsResult> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ import cn.topiam.employee.audit.repository.result.AuthnQuantityResult;
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/10/04 22:25
 | 
			
		||||
 * Created by support@topiam.cn on 2023/10/04 22:25
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("DuplicatedCode")
 | 
			
		||||
public class AuthnQuantityResultMapper implements RowMapper<AuthnQuantityResult> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,9 +19,9 @@ package cn.topiam.employee.audit.service;
 | 
			
		|||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.Page;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.PageModel;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ import cn.topiam.employee.support.repository.page.domain.PageModel;
 | 
			
		|||
 * 审计service
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/10 23:06
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/10 23:06
 | 
			
		||||
 */
 | 
			
		||||
public interface AuditService {
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,37 +20,23 @@ package cn.topiam.employee.audit.service.converter;
 | 
			
		|||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.mapstruct.Mapper;
 | 
			
		||||
import org.springframework.data.jpa.domain.Specification;
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
import org.springframework.util.StringUtils;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.entity.AuditEntity;
 | 
			
		||||
import cn.topiam.employee.audit.entity.Target;
 | 
			
		||||
import cn.topiam.employee.audit.enums.TargetType;
 | 
			
		||||
import cn.topiam.employee.common.entity.account.OrganizationEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.account.UserEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.account.UserGroupEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.app.AppEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.authn.IdentityProviderEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.identitysource.IdentitySourceEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.setting.AdministratorEntity;
 | 
			
		||||
import cn.topiam.employee.common.entity.setting.MailTemplateEntity;
 | 
			
		||||
import cn.topiam.employee.common.repository.account.OrganizationRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.account.UserGroupRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.account.UserRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.app.AppRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.identitysource.IdentitySourceRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.setting.AdministratorRepository;
 | 
			
		||||
import cn.topiam.employee.common.repository.setting.MailTemplateRepository;
 | 
			
		||||
import cn.topiam.employee.support.context.ApplicationContextHelp;
 | 
			
		||||
import cn.topiam.employee.support.context.ApplicationContextService;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.Page;
 | 
			
		||||
import cn.topiam.employee.support.repository.page.domain.PageModel;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserDetails;
 | 
			
		||||
import cn.topiam.employee.support.security.userdetails.UserType;
 | 
			
		||||
import cn.topiam.employee.support.security.util.SecurityUtils;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +66,7 @@ public interface AuditDataConverter {
 | 
			
		|||
        //总记录数
 | 
			
		||||
        auditEntityPage.forEach(audit -> {
 | 
			
		||||
            AuditListResult result = new AuditListResult();
 | 
			
		||||
            result.setId(audit.getId().toString());
 | 
			
		||||
            result.setId(audit.getId());
 | 
			
		||||
            result.setEventStatus(audit.getEventStatus());
 | 
			
		||||
            result.setEventType(audit.getEventType().getDesc());
 | 
			
		||||
            result.setEventTime(audit.getEventTime());
 | 
			
		||||
| 
						 | 
				
			
			@ -93,14 +79,6 @@ public interface AuditDataConverter {
 | 
			
		|||
            //用户类型
 | 
			
		||||
            result.setUserType(audit.getActorType().getType());
 | 
			
		||||
            //操作对象
 | 
			
		||||
            if (Objects.nonNull(audit.getTargets())) {
 | 
			
		||||
                for (Target target : audit.getTargets()) {
 | 
			
		||||
                    if (Objects.nonNull(target.getId())) {
 | 
			
		||||
                        target.setName(getTargetName(target.getType(), target.getId()));
 | 
			
		||||
                    }
 | 
			
		||||
                    target.setTypeName(target.getType().getDesc());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            result.setTargets(audit.getTargets());
 | 
			
		||||
            list.add(result);
 | 
			
		||||
        });
 | 
			
		||||
| 
						 | 
				
			
			@ -128,14 +106,14 @@ public interface AuditDataConverter {
 | 
			
		|||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        if (UserType.USER.equals(actorType)) {
 | 
			
		||||
            UserRepository repository = ApplicationContextHelp.getBean(UserRepository.class);
 | 
			
		||||
            UserEntity user = repository.findById(Long.valueOf(actorId)).orElse(new UserEntity());
 | 
			
		||||
            UserRepository repository = ApplicationContextService.getBean(UserRepository.class);
 | 
			
		||||
            UserEntity user = repository.findById(actorId).orElse(new UserEntity());
 | 
			
		||||
            return Objects.toString(user.getFullName(), user.getUsername());
 | 
			
		||||
        }
 | 
			
		||||
        if (UserType.ADMIN.equals(actorType)) {
 | 
			
		||||
            AdministratorRepository repository = ApplicationContextHelp
 | 
			
		||||
            AdministratorRepository repository = ApplicationContextService
 | 
			
		||||
                .getBean(AdministratorRepository.class);
 | 
			
		||||
            AdministratorEntity administrator = repository.findById(Long.valueOf(actorId))
 | 
			
		||||
            AdministratorEntity administrator = repository.findById(actorId)
 | 
			
		||||
                .orElse(new AdministratorEntity());
 | 
			
		||||
            return administrator.getUsername();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -153,46 +131,35 @@ public interface AuditDataConverter {
 | 
			
		|||
        return (root, criteriaQuery, criteriaBuilder) -> {
 | 
			
		||||
            ArrayList<Predicate> predicates = new ArrayList<>();
 | 
			
		||||
            ArrayList<Order> orders = new ArrayList<>();
 | 
			
		||||
            UserType userType = SecurityUtils.getCurrentUser().getUserType();
 | 
			
		||||
            UserDetails currentUser = SecurityUtils.getCurrentUser();
 | 
			
		||||
            UserType loginUserType = currentUser.getUserType();
 | 
			
		||||
            // 登录角色 管理员
 | 
			
		||||
            if (UserType.ADMIN.equals(userType)) {
 | 
			
		||||
            String actorId = null;
 | 
			
		||||
            if (UserType.ADMIN.equals(loginUserType)) {
 | 
			
		||||
                if (StringUtils.hasText(query.getUsername())) {
 | 
			
		||||
                    String actorId = "";
 | 
			
		||||
                    if (UserType.USER.getType().equals(query.getUserType())) {
 | 
			
		||||
                        UserRepository userRepository = ApplicationContextHelp
 | 
			
		||||
                            .getBean(UserRepository.class);
 | 
			
		||||
                        UserEntity user = userRepository.findByUsername(query.getUsername());
 | 
			
		||||
                        if (!Objects.isNull(user)) {
 | 
			
		||||
                            actorId = user.getId().toString();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (UserType.ADMIN.getType().equals(query.getUserType())) {
 | 
			
		||||
                        AdministratorRepository administratorRepository = ApplicationContextHelp
 | 
			
		||||
                            .getBean(AdministratorRepository.class);
 | 
			
		||||
                        Optional<AdministratorEntity> optional = administratorRepository
 | 
			
		||||
                            .findByUsername(query.getUsername());
 | 
			
		||||
                        if (optional.isPresent()) {
 | 
			
		||||
                            actorId = optional.get().getId().toString();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (StringUtils.hasText(actorId)) {
 | 
			
		||||
                        predicates.add(criteriaBuilder.equal(root.get("actorId"), actorId));
 | 
			
		||||
                    UserRepository userRepository = ApplicationContextService
 | 
			
		||||
                        .getBean(UserRepository.class);
 | 
			
		||||
                    List<UserEntity> userList = userRepository
 | 
			
		||||
                        .findByFullNameLike("%" + query.getUsername() + "%");
 | 
			
		||||
                    // 模糊匹配
 | 
			
		||||
                    if (!CollectionUtils.isEmpty(userList)) {
 | 
			
		||||
                        List<String> userIds = userList.stream().map(UserEntity::getId).toList();
 | 
			
		||||
                        predicates.add(criteriaBuilder.in(root.get("actorId")).value(userIds));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return null;
 | 
			
		||||
                    }
 | 
			
		||||
                } else if (UserType.ADMIN.getType().equals(query.getUserType())) {
 | 
			
		||||
                    actorId = currentUser.getId();
 | 
			
		||||
                }
 | 
			
		||||
                // 用户类型
 | 
			
		||||
                if (UserType.USER.getType().equals(query.getUserType())) {
 | 
			
		||||
                    predicates.add(criteriaBuilder.equal(root.get("actorType"), UserType.USER));
 | 
			
		||||
                }
 | 
			
		||||
                if (UserType.ADMIN.getType().equals(query.getUserType())) {
 | 
			
		||||
                    predicates.add(criteriaBuilder.equal(root.get("actorType"), UserType.ADMIN));
 | 
			
		||||
                }
 | 
			
		||||
                predicates.add(criteriaBuilder.equal(root.get("actorType"), query.getUserType()));
 | 
			
		||||
            }
 | 
			
		||||
            // 登录角色 用户
 | 
			
		||||
            if (UserType.USER.equals(userType)) {
 | 
			
		||||
                predicates.add(criteriaBuilder.equal(root.get("actorId"),
 | 
			
		||||
                    SecurityUtils.getCurrentUser().getId()));
 | 
			
		||||
                // 用户类型
 | 
			
		||||
                predicates.add(criteriaBuilder.equal(root.get("actorType"), UserType.USER));
 | 
			
		||||
            if (UserType.USER.equals(loginUserType)) {
 | 
			
		||||
                actorId = currentUser.getId();
 | 
			
		||||
            }
 | 
			
		||||
            if (StringUtils.hasText(actorId)) {
 | 
			
		||||
                predicates.add(criteriaBuilder.equal(root.get("actorId"), currentUser.getId()));
 | 
			
		||||
            }
 | 
			
		||||
            // 事件类型
 | 
			
		||||
            if (!CollectionUtils.isEmpty(query.getEventType())) {
 | 
			
		||||
| 
						 | 
				
			
			@ -205,8 +172,8 @@ public interface AuditDataConverter {
 | 
			
		|||
                    .add(criteriaBuilder.equal(root.get("eventStatus"), query.getEventStatus()));
 | 
			
		||||
            }
 | 
			
		||||
            // 事件时间
 | 
			
		||||
            if (!Objects.isNull(query.getStartEventTime())
 | 
			
		||||
                && !Objects.isNull(query.getEndEventTime())) {
 | 
			
		||||
            if (Objects.nonNull(query.getStartEventTime())
 | 
			
		||||
                && Objects.nonNull(query.getEndEventTime())) {
 | 
			
		||||
                predicates.add(criteriaBuilder.between(root.get("eventTime"),
 | 
			
		||||
                    query.getStartEventTime(), query.getEndEventTime()));
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -225,91 +192,4 @@ public interface AuditDataConverter {
 | 
			
		|||
            return criteriaQuery.getRestriction();
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取目标名称
 | 
			
		||||
     *
 | 
			
		||||
     * @param targetType {@link TargetType}
 | 
			
		||||
     * @param id         {@link String}
 | 
			
		||||
     * @return {@link String}
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("AlibabaMethodTooLong")
 | 
			
		||||
    default String getTargetName(TargetType targetType, String id) {
 | 
			
		||||
        //@formatter:off
 | 
			
		||||
        String name = "";
 | 
			
		||||
        if (TargetType.USER.equals(targetType) || TargetType.USER_DETAIL.equals(targetType)) {
 | 
			
		||||
            UserRepository userRepository = ApplicationContextHelp.getBean(UserRepository.class);
 | 
			
		||||
            Optional<UserEntity> user = userRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (user.isPresent()) {
 | 
			
		||||
                UserEntity entity = user.get();
 | 
			
		||||
                name = Objects.toString(entity.getFullName(),
 | 
			
		||||
                    entity.getUsername());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //用户组
 | 
			
		||||
        if (TargetType.USER_GROUP.equals(targetType)) {
 | 
			
		||||
            UserGroupRepository userGroupRepository = ApplicationContextHelp.getBean(UserGroupRepository.class);
 | 
			
		||||
            Optional<UserGroupEntity> userGroup = userGroupRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (userGroup.isPresent()) {
 | 
			
		||||
                name = userGroup.get().getName();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //身份源
 | 
			
		||||
        if (TargetType.IDENTITY_SOURCE.equals(targetType)) {
 | 
			
		||||
            IdentitySourceRepository identitySourceRepository = ApplicationContextHelp.getBean(IdentitySourceRepository.class);
 | 
			
		||||
            Optional<IdentitySourceEntity> identitySource = identitySourceRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (identitySource.isPresent()) {
 | 
			
		||||
                name = identitySource.get().getName();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //组织机构
 | 
			
		||||
        if (TargetType.ORGANIZATION.equals(targetType)) {
 | 
			
		||||
            OrganizationRepository organizationRepository = ApplicationContextHelp.getBean(OrganizationRepository.class);
 | 
			
		||||
            Optional<OrganizationEntity> organizationEntity = organizationRepository.findByIdContainsDeleted(id);
 | 
			
		||||
            if (organizationEntity.isPresent()) {
 | 
			
		||||
                name = organizationEntity.get().getName();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //应用
 | 
			
		||||
        if (TargetType.APPLICATION.equals(targetType)) {
 | 
			
		||||
            AppRepository appRepository = ApplicationContextHelp.getBean(AppRepository.class);
 | 
			
		||||
            Optional<AppEntity> appEntity = appRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (appEntity.isPresent()) {
 | 
			
		||||
                name = appEntity.get().getName();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //应用账户
 | 
			
		||||
        if (TargetType.APPLICATION_ACCOUNT.equals(targetType)) {
 | 
			
		||||
            if (org.apache.commons.lang3.StringUtils.isNotBlank(id)) {
 | 
			
		||||
                name = id;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //管理员
 | 
			
		||||
        if (TargetType.ADMINISTRATOR.equals(targetType)) {
 | 
			
		||||
            AdministratorRepository administratorRepository = ApplicationContextHelp.getBean(AdministratorRepository.class);
 | 
			
		||||
            Optional<AdministratorEntity> administratorEntity = administratorRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (administratorEntity.isPresent()) {
 | 
			
		||||
                name = administratorEntity.get().getUsername();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //邮件模版
 | 
			
		||||
        if (TargetType.MAIL_TEMPLATE.equals(targetType)) {
 | 
			
		||||
            MailTemplateRepository mailTemplateRepository = ApplicationContextHelp.getBean(MailTemplateRepository.class);
 | 
			
		||||
            Optional<MailTemplateEntity> mailTemplateEntity = mailTemplateRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (mailTemplateEntity.isPresent()) {
 | 
			
		||||
                name = mailTemplateEntity.get().getSender();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        //身份提供商
 | 
			
		||||
        if (TargetType.IDENTITY_PROVIDER.equals(targetType)) {
 | 
			
		||||
            IdentityProviderRepository identityProviderRepository = ApplicationContextHelp.getBean(IdentityProviderRepository.class);
 | 
			
		||||
            Optional<IdentityProviderEntity> identityProviderEntity = identityProviderRepository.findByIdContainsDeleted(Long.valueOf(id));
 | 
			
		||||
            if (identityProviderEntity.isPresent()) {
 | 
			
		||||
                name = identityProviderEntity.get().getName();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return name;
 | 
			
		||||
        //@formatter:on
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,20 +17,18 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.audit.service.impl;
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.LinkedHashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.domain.PageRequest;
 | 
			
		||||
import org.springframework.data.domain.Sort;
 | 
			
		||||
import org.springframework.data.jpa.domain.Specification;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.util.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.controller.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListQuery;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.AuditListResult;
 | 
			
		||||
import cn.topiam.employee.audit.endpoint.pojo.DictResult;
 | 
			
		||||
import cn.topiam.employee.audit.entity.AuditEntity;
 | 
			
		||||
import cn.topiam.employee.audit.event.type.EventType;
 | 
			
		||||
import cn.topiam.employee.audit.repository.AuditRepository;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +47,7 @@ import static cn.topiam.employee.support.security.userdetails.UserType.USER;
 | 
			
		|||
 * 审计 service impl
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2021/9/10 23:06
 | 
			
		||||
 * Created by support@topiam.cn on 2021/9/10 23:06
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
| 
						 | 
				
			
			@ -71,9 +69,18 @@ public class AuditServiceImpl implements AuditService {
 | 
			
		|||
        //查询入参转查询条件
 | 
			
		||||
        Specification<AuditEntity> specification = auditDataConverter
 | 
			
		||||
            .auditListRequestConvertToSpecification(query, page);
 | 
			
		||||
 | 
			
		||||
        if (Objects.isNull(specification)) {
 | 
			
		||||
            return new Page<>();
 | 
			
		||||
        }
 | 
			
		||||
        // 排序
 | 
			
		||||
        List<Sort.Order> orders = new ArrayList<>();
 | 
			
		||||
        for (PageModel.Sort sort : page.getSorts()) {
 | 
			
		||||
            orders.add(new Sort.Order((sort.getAsc() ? Sort.Direction.ASC : Sort.Direction.DESC),
 | 
			
		||||
                sort.getSorter()));
 | 
			
		||||
        }
 | 
			
		||||
        //分页条件
 | 
			
		||||
        PageRequest request = PageRequest.of(page.getCurrent(), page.getPageSize());
 | 
			
		||||
        PageRequest request = PageRequest.of(page.getCurrent(), page.getPageSize(),
 | 
			
		||||
            Sort.by(orders));
 | 
			
		||||
        //查询列表
 | 
			
		||||
        return auditDataConverter
 | 
			
		||||
            .entityConvertToAuditListResult(auditRepository.findAll(specification, request), page);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,10 +21,10 @@
 | 
			
		|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
			
		||||
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
			
		||||
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
    <parent>
 | 
			
		||||
      <parent>
 | 
			
		||||
        <artifactId>eiam-authentication</artifactId>
 | 
			
		||||
        <groupId>cn.topiam</groupId>
 | 
			
		||||
        <version>1.0.2-SNAPSHOT</version>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
        <relativePath>../pom.xml</relativePath>
 | 
			
		||||
    </parent>
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.authentication.alipay;
 | 
			
		||||
 | 
			
		||||
import cn.topiam.employee.authentication.common.config.IdentityProviderConfig;
 | 
			
		||||
import cn.topiam.employee.authentication.common.client.IdentityProviderConfig;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +28,11 @@ import jakarta.validation.constraints.NotBlank;
 | 
			
		|||
 * 支付宝 登录配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/8/19 16:09
 | 
			
		||||
 * Created by support@topiam.cn on 2023/8/19 16:09
 | 
			
		||||
 */
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
public class AlipayIdpOAuth2Config extends IdentityProviderConfig {
 | 
			
		||||
public class AlipayIdentityProviderOAuth2Config extends IdentityProviderConfig {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 商户ID
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ import com.aliyun.tea.*;
 | 
			
		|||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/8/25 22:26
 | 
			
		||||
 * Created by support@topiam.cn on 2023/8/25 22:26
 | 
			
		||||
 */
 | 
			
		||||
public class AlipayClient {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +42,11 @@ public class AlipayClient {
 | 
			
		|||
     * @throws Exception Exception
 | 
			
		||||
     */
 | 
			
		||||
    public AlipaySystemOauthTokenResponse getOauthToken(String code) throws Exception {
 | 
			
		||||
        java.util.Map<String, Object> runtime = getRuntime();
 | 
			
		||||
        Map<String, Object> runtime = getRuntime();
 | 
			
		||||
        TeaRequest request = null;
 | 
			
		||||
        long now = System.currentTimeMillis();
 | 
			
		||||
        int retryTimes = 0;
 | 
			
		||||
        while (Tea.allowRetry((java.util.Map<String, Object>) runtime.get("retry"), retryTimes,
 | 
			
		||||
            now)) {
 | 
			
		||||
        while (Tea.allowRetry((Map<String, Object>) runtime.get("retry"), retryTimes, now)) {
 | 
			
		||||
            if (retryTimes > 0) {
 | 
			
		||||
                int backoffTime = Tea.getBackoffTime(runtime.get("backoff"), retryTimes);
 | 
			
		||||
                if (backoffTime > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -57,7 +56,7 @@ public class AlipayClient {
 | 
			
		|||
            retryTimes = retryTimes + 1;
 | 
			
		||||
            try {
 | 
			
		||||
                //@formatter:off
 | 
			
		||||
                java.util.Map<String, String> systemParams = TeaConverter.buildMap(
 | 
			
		||||
                Map<String, String> systemParams = TeaConverter.buildMap(
 | 
			
		||||
                    new TeaPair("method", "alipay.system.oauth.token"),
 | 
			
		||||
                    new TeaPair("app_id", kernel.getConfig("appId")),
 | 
			
		||||
                    new TeaPair("timestamp", kernel.getTimestamp()),
 | 
			
		||||
| 
						 | 
				
			
			@ -68,13 +67,13 @@ public class AlipayClient {
 | 
			
		|||
                    new TeaPair("app_cert_sn", kernel.getMerchantCertSN()),
 | 
			
		||||
                    new TeaPair("alipay_root_cert_sn", kernel.getAlipayRootCertSN()));
 | 
			
		||||
                //@formatter:no
 | 
			
		||||
                java.util.Map<String, Object> bizParams = new java.util.HashMap<>();
 | 
			
		||||
                java.util.Map<String, String> textParams = TeaConverter.buildMap(
 | 
			
		||||
                Map<String, Object> bizParams = new java.util.HashMap<>();
 | 
			
		||||
                Map<String, String> 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<String, Object> respMap = kernel.readAsJson(response,
 | 
			
		||||
                Map<String, Object> respMap = kernel.readAsJson(response,
 | 
			
		||||
                    "alipay.system.oauth.token");
 | 
			
		||||
                if (kernel.isCertMode()) {
 | 
			
		||||
                    if (kernel.verify(respMap,
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +121,7 @@ public class AlipayClient {
 | 
			
		|||
        return request;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private java.util.Map<String, Object> getRuntime() throws Exception {
 | 
			
		||||
    private Map<String, Object> 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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,9 @@
 | 
			
		|||
 */
 | 
			
		||||
package cn.topiam.employee.authentication.alipay.client;
 | 
			
		||||
 | 
			
		||||
import com.aliyun.tea.*;
 | 
			
		||||
import com.aliyun.tea.NameInMap;
 | 
			
		||||
import com.aliyun.tea.TeaModel;
 | 
			
		||||
import com.aliyun.tea.Validation;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +27,7 @@ import lombok.Setter;
 | 
			
		|||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/8/25 22:26
 | 
			
		||||
 * Created by support@topiam.cn on 2023/8/25 22:26
 | 
			
		||||
 */
 | 
			
		||||
@Getter
 | 
			
		||||
@Setter
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,8 +29,8 @@ import org.springframework.util.Assert;
 | 
			
		|||
 | 
			
		||||
import cn.topiam.employee.authentication.alipay.filter.AlipayAuthorizationRequestRedirectFilter;
 | 
			
		||||
import cn.topiam.employee.authentication.alipay.filter.AlipayLoginAuthenticationFilter;
 | 
			
		||||
import cn.topiam.employee.authentication.common.service.UserIdpService;
 | 
			
		||||
import cn.topiam.employee.common.repository.authentication.IdentityProviderRepository;
 | 
			
		||||
import cn.topiam.employee.authentication.common.IdentityProviderAuthenticationService;
 | 
			
		||||
import cn.topiam.employee.authentication.common.client.RegisteredIdentityProviderClientRepository;
 | 
			
		||||
 | 
			
		||||
import lombok.NonNull;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
| 
						 | 
				
			
			@ -40,36 +40,38 @@ import static cn.topiam.employee.support.security.util.HttpSecurityFilterOrderRe
 | 
			
		|||
 * 认证配置
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/8/19 15:52
 | 
			
		||||
 * Created by support@topiam.cn on 2023/8/19 15:52
 | 
			
		||||
 */
 | 
			
		||||
public class AlipayAuthenticationConfigurer extends
 | 
			
		||||
                                            AbstractAuthenticationFilterConfigurer<HttpSecurity, AlipayAuthenticationConfigurer, AlipayLoginAuthenticationFilter> {
 | 
			
		||||
    @Setter
 | 
			
		||||
    @NonNull
 | 
			
		||||
    private String                           loginProcessingUrl = AlipayLoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
 | 
			
		||||
    private String                                           loginProcessingUrl = AlipayLoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI;
 | 
			
		||||
 | 
			
		||||
    private final IdentityProviderRepository identityProviderRepository;
 | 
			
		||||
    private final UserIdpService             userIdpService;
 | 
			
		||||
    private final RegisteredIdentityProviderClientRepository registeredIdentityProviderClientRepository;
 | 
			
		||||
    private final IdentityProviderAuthenticationService      identityProviderAuthenticationService;
 | 
			
		||||
 | 
			
		||||
    AlipayAuthenticationConfigurer(IdentityProviderRepository identityProviderRepository,
 | 
			
		||||
                                   UserIdpService userIdpService) {
 | 
			
		||||
        Assert.notNull(identityProviderRepository, "identityProviderRepository must not be null");
 | 
			
		||||
        Assert.notNull(userIdpService, "userIdpService must not be null");
 | 
			
		||||
        this.identityProviderRepository = identityProviderRepository;
 | 
			
		||||
        this.userIdpService = userIdpService;
 | 
			
		||||
    AlipayAuthenticationConfigurer(RegisteredIdentityProviderClientRepository registeredIdentityProviderClientRepository,
 | 
			
		||||
                                   IdentityProviderAuthenticationService identityProviderAuthenticationService) {
 | 
			
		||||
        Assert.notNull(registeredIdentityProviderClientRepository,
 | 
			
		||||
            "registeredIdentityProviderClientRepository must not be null");
 | 
			
		||||
        Assert.notNull(identityProviderAuthenticationService, "userIdpService must not be null");
 | 
			
		||||
        this.registeredIdentityProviderClientRepository = registeredIdentityProviderClientRepository;
 | 
			
		||||
        this.identityProviderAuthenticationService = identityProviderAuthenticationService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void init(HttpSecurity http) throws Exception {
 | 
			
		||||
        //支付宝登录认证
 | 
			
		||||
        this.setAuthenticationFilter(
 | 
			
		||||
            new AlipayLoginAuthenticationFilter(userIdpService, identityProviderRepository));
 | 
			
		||||
        this.setAuthenticationFilter(new AlipayLoginAuthenticationFilter(
 | 
			
		||||
            identityProviderAuthenticationService, registeredIdentityProviderClientRepository));
 | 
			
		||||
        putFilterBefore(http, this.getAuthenticationFilter(),
 | 
			
		||||
            OAuth2LoginAuthenticationFilter.class);
 | 
			
		||||
 | 
			
		||||
        //支付宝请求重定向
 | 
			
		||||
        http.addFilterBefore(
 | 
			
		||||
            new AlipayAuthorizationRequestRedirectFilter(identityProviderRepository),
 | 
			
		||||
            new AlipayAuthorizationRequestRedirectFilter(
 | 
			
		||||
                registeredIdentityProviderClientRepository),
 | 
			
		||||
            OAuth2AuthorizationRequestRedirectFilter.class);
 | 
			
		||||
 | 
			
		||||
        //登录处理地址
 | 
			
		||||
| 
						 | 
				
			
			@ -94,8 +96,9 @@ public class AlipayAuthenticationConfigurer extends
 | 
			
		|||
            AlipayLoginAuthenticationFilter.getRequestMatcher());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static AlipayAuthenticationConfigurer alipayOauth(IdentityProviderRepository identityProviderRepository,
 | 
			
		||||
                                                             UserIdpService userIdpService) {
 | 
			
		||||
        return new AlipayAuthenticationConfigurer(identityProviderRepository, userIdpService);
 | 
			
		||||
    public static AlipayAuthenticationConfigurer alipayOauth(RegisteredIdentityProviderClientRepository registeredIdentityProviderClientRepository,
 | 
			
		||||
                                                             IdentityProviderAuthenticationService identityProviderAuthenticationService) {
 | 
			
		||||
        return new AlipayAuthenticationConfigurer(registeredIdentityProviderClientRepository,
 | 
			
		||||
            identityProviderAuthenticationService);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ package cn.topiam.employee.authentication.alipay.constant;
 | 
			
		|||
 * 支付宝 认证常量
 | 
			
		||||
 *
 | 
			
		||||
 * @author TopIAM
 | 
			
		||||
 * Created by support@topiam.cn on  2023/8/19 15:18
 | 
			
		||||
 * Created by support@topiam.cn on 2023/8/19 15:18
 | 
			
		||||
 */
 | 
			
		||||
public class AlipayAuthenticationConstants {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue