mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 05:36:23 +00:00
feat: user 서비스 redis/eventhub 환경설정 및 로그인API 추가
This commit is contained in:
parent
0da631b8e7
commit
66885c7ed6
@ -3,8 +3,54 @@
|
||||
<ExternalSystemSettings>
|
||||
<option name="env">
|
||||
<map>
|
||||
<!-- Database Configuration -->x
|
||||
<entry key="DB_KIND" value="postgresql" />
|
||||
<entry key="DB_HOST" value="20.214.121.121" />
|
||||
<entry key="DB_PORT" value="5432" />
|
||||
<entry key="DB_NAME" value="userdb" />
|
||||
<entry key="DB_USERNAME" value="hgzerouser" />
|
||||
<entry key="DB_PASSWORD" value="Hi5Jessica!" />
|
||||
<entry key="JWT_SECRET" value="my-super-secret-jwt-key-for-hgzero-meeting-service-2024" />
|
||||
|
||||
<!-- JPA Configuration -->
|
||||
<entry key="SHOW_SQL" value="true" />
|
||||
<entry key="JPA_DDL_AUTO" value="update" />
|
||||
|
||||
<!-- Redis Configuration -->
|
||||
<entry key="REDIS_HOST" value="20.249.177.114" />
|
||||
<entry key="REDIS_PORT" value="6379" />
|
||||
<entry key="REDIS_PASSWORD" value="Hi5Jessica!" />
|
||||
<entry key="REDIS_DATABASE" value="1" />
|
||||
|
||||
<!-- Server Configuration -->
|
||||
<entry key="SERVER_PORT" value="8081" />
|
||||
|
||||
<!-- Redis Configuration -->
|
||||
<entry key="REDIS_HOST" value="20.249.177.114" />
|
||||
<entry key="REDIS_PORT" value="6379" />
|
||||
<entry key="REDIS_PASSWORD" value="Hi5Jessica!" />
|
||||
<entry key="REDIS_DATABASE" value="1" />
|
||||
|
||||
<!-- Spring Profile -->
|
||||
<entry key="SPRING_PROFILES_ACTIVE" value="dev" />
|
||||
|
||||
<!-- Azure EventHub Configuration -->
|
||||
<entry key="EVENTHUB_CONNECTION_STRING" value="Endpoint=sb://hgzero-eventhub-ns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=VUqZ9vFgu35E3c6RiUzoOGVUP8IZpFvlV+AEhC6sUpo=" />
|
||||
<entry key="EVENTHUB_NAME" value="hgzero-eventhub-name" />
|
||||
<entry key="EVENTHUB_CONSUMER_GROUP" value="$Default" />
|
||||
|
||||
<!-- Logging Configuration -->
|
||||
<entry key="LOG_LEVEL_ROOT" value="INFO" />
|
||||
<entry key="LOG_LEVEL_APP" value="DEBUG" />
|
||||
<entry key="LOG_LEVEL_WEB" value="INFO" />
|
||||
<entry key="LOG_LEVEL_SECURITY" value="DEBUG" />
|
||||
<entry key="LOG_LEVEL_WEBSOCKET" value="DEBUG" />
|
||||
<entry key="LOG_LEVEL_SQL" value="DEBUG" />
|
||||
<entry key="LOG_LEVEL_SQL_TYPE" value="TRACE" />
|
||||
<entry key="LOG_FILE" value="logs/user-service.log" />
|
||||
<entry key="LOG_MAX_FILE_SIZE" value="10MB" />
|
||||
<entry key="LOG_MAX_HISTORY" value="7" />
|
||||
<entry key="LOG_TOTAL_SIZE_CAP" value="100MB" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="executionName" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
BIN
user/logs/user-service.log.2025-10-24.0.gz
Normal file
BIN
user/logs/user-service.log.2025-10-24.0.gz
Normal file
Binary file not shown.
@ -0,0 +1,91 @@
|
||||
package com.unicorn.hgzero.user.config;
|
||||
|
||||
import io.lettuce.core.ClientOptions;
|
||||
import io.lettuce.core.ReadFrom;
|
||||
import io.lettuce.core.SocketOptions;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* Redis 설정
|
||||
* Lettuce 클라이언트를 사용하여 Redis 연결 및 템플릿 구성
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Value("${spring.data.redis.host:localhost}")
|
||||
private String host;
|
||||
|
||||
@Value("${spring.data.redis.port:6379}")
|
||||
private int port;
|
||||
|
||||
@Value("${spring.data.redis.password:}")
|
||||
private String password;
|
||||
|
||||
@Value("${spring.data.redis.database:0}")
|
||||
private int database;
|
||||
|
||||
/**
|
||||
* Redis 연결 팩토리 설정
|
||||
* ReadFrom.MASTER로 설정하여 마스터에서만 읽기/쓰기 수행
|
||||
*/
|
||||
@Bean
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
// Redis Standalone 설정
|
||||
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
|
||||
redisStandaloneConfiguration.setHostName(host);
|
||||
redisStandaloneConfiguration.setPort(port);
|
||||
redisStandaloneConfiguration.setDatabase(database);
|
||||
|
||||
// 비밀번호가 있는 경우에만 설정
|
||||
if (password != null && !password.isEmpty()) {
|
||||
redisStandaloneConfiguration.setPassword(password);
|
||||
}
|
||||
|
||||
// Lettuce 클라이언트 설정
|
||||
SocketOptions socketOptions = SocketOptions.builder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
|
||||
ClientOptions clientOptions = ClientOptions.builder()
|
||||
.socketOptions(socketOptions)
|
||||
.build();
|
||||
|
||||
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
|
||||
.clientOptions(clientOptions)
|
||||
.commandTimeout(Duration.ofSeconds(5))
|
||||
.readFrom(ReadFrom.MASTER) // 마스터에서만 읽기/쓰기
|
||||
.build();
|
||||
|
||||
return new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* RedisTemplate 설정
|
||||
* String 키와 값을 사용하는 템플릿 구성
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, String> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
// String 직렬화 설정
|
||||
StringRedisSerializer stringSerializer = new StringRedisSerializer();
|
||||
template.setKeySerializer(stringSerializer);
|
||||
template.setValueSerializer(stringSerializer);
|
||||
template.setHashKeySerializer(stringSerializer);
|
||||
template.setHashValueSerializer(stringSerializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,8 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHt
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
@ -69,7 +71,8 @@ public class SecurityConfig {
|
||||
// 허용할 헤더
|
||||
configuration.setAllowedHeaders(Arrays.asList(
|
||||
"Authorization", "Content-Type", "X-Requested-With", "Accept",
|
||||
"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"
|
||||
"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers",
|
||||
"X-User-Id", "X-User-Name", "X-User-Email"
|
||||
));
|
||||
|
||||
// 자격 증명 허용
|
||||
@ -82,4 +85,24 @@ public class SecurityConfig {
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* HttpFirewall 설정
|
||||
* 한글을 포함한 모든 문자를 헤더 값으로 허용
|
||||
*/
|
||||
@Bean
|
||||
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
|
||||
StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||
|
||||
// 한글을 포함한 모든 문자를 허용하도록 설정
|
||||
firewall.setAllowedHeaderValues(header -> true);
|
||||
|
||||
// URL 인코딩된 슬래시 허용
|
||||
firewall.setAllowUrlEncodedSlash(true);
|
||||
|
||||
// 세미콜론 허용
|
||||
firewall.setAllowSemicolon(true);
|
||||
|
||||
return firewall;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
return path.startsWith("/actuator") ||
|
||||
path.startsWith("/swagger-ui") ||
|
||||
path.startsWith("/v3/api-docs") ||
|
||||
path.equals("/health");
|
||||
path.equals("/health") ||
|
||||
path.equals("/api/v1/auth/login");
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,209 @@
|
||||
package com.unicorn.hgzero.user.config.ldap;
|
||||
|
||||
import com.unicorn.hgzero.common.exception.BusinessException;
|
||||
import com.unicorn.hgzero.common.exception.ErrorCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.ldap.core.AttributesMapper;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.ldap.filter.EqualsFilter;
|
||||
import org.springframework.ldap.filter.Filter;
|
||||
import org.springframework.ldap.support.LdapUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* LDAP 인증 및 사용자 정보 조회 클래스
|
||||
*
|
||||
* LDAP 서버와의 인증 처리 및 사용자 속성 조회 기능 제공
|
||||
* - LDAPS (포트 636) 사용
|
||||
* - 타임아웃: 5초
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LdapAuthenticator {
|
||||
|
||||
private final LdapTemplate ldapTemplate;
|
||||
|
||||
@Value("${spring.ldap.user-dn-pattern:uid={0},ou=people}")
|
||||
private String userDnPattern;
|
||||
|
||||
@Value("${spring.ldap.user-search-base:ou=people}")
|
||||
private String userSearchBase;
|
||||
|
||||
@Value("${spring.profiles.active:dev}")
|
||||
private String activeProfile;
|
||||
|
||||
/**
|
||||
* LDAP 인증 및 사용자 정보 조회
|
||||
*
|
||||
* @param username 사용자 ID
|
||||
* @param password 비밀번호
|
||||
* @return LDAP 사용자 정보
|
||||
* @throws BusinessException 인증 실패 시
|
||||
*/
|
||||
public LdapUserDetails validateCredentials(String username, String password) {
|
||||
log.debug("LDAP 인증 시도: username={}, profile={}", username, activeProfile);
|
||||
|
||||
// 개발 환경에서는 LDAP 인증 건너뛰기
|
||||
if ("dev".equals(activeProfile)) {
|
||||
log.info("개발 환경 - LDAP 인증 건너뛰기: username={}", username);
|
||||
return createDefaultUserDetails(username);
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. LDAP bind (인증)
|
||||
boolean authenticated = authenticate(username, password);
|
||||
if (!authenticated) {
|
||||
log.warn("LDAP 인증 실패: username={}", username);
|
||||
throw new BusinessException(ErrorCode.AUTHENTICATION_FAILED);
|
||||
}
|
||||
|
||||
log.info("LDAP 인증 성공: username={}", username);
|
||||
|
||||
// 2. 사용자 정보 조회
|
||||
LdapUserDetails userDetails = searchUser(username);
|
||||
log.debug("LDAP 사용자 정보 조회 완료: username={}, email={}", username, userDetails.getEmail());
|
||||
|
||||
return userDetails;
|
||||
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("LDAP 인증 중 오류 발생: username={}, error={}", username, e.getMessage(), e);
|
||||
throw new BusinessException(ErrorCode.AUTHENTICATION_FAILED, "LDAP 인증 중 오류가 발생했습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LDAP 인증 수행
|
||||
*
|
||||
* @param username 사용자 ID
|
||||
* @param password 비밀번호
|
||||
* @return 인증 성공 여부
|
||||
*/
|
||||
private boolean authenticate(String username, String password) {
|
||||
try {
|
||||
// EqualsFilter를 사용하여 uid로 검색
|
||||
Filter filter = new EqualsFilter("uid", username);
|
||||
|
||||
// LDAP 인증 수행
|
||||
// Protocol: LDAPS (636), Timeout: 5s (LdapTemplate 설정에서 관리)
|
||||
boolean authenticated = ldapTemplate.authenticate(
|
||||
userSearchBase,
|
||||
filter.encode(),
|
||||
password
|
||||
);
|
||||
|
||||
return authenticated;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("LDAP bind 실패: username={}, error={}", username, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LDAP에서 사용자 정보 조회
|
||||
*
|
||||
* 조회 속성:
|
||||
* - cn (Common Name): 사용자 이름
|
||||
* - mail: 이메일
|
||||
* - department: 부서
|
||||
* - title: 직급
|
||||
*
|
||||
* @param username 사용자 ID
|
||||
* @return LDAP 사용자 정보
|
||||
*/
|
||||
private LdapUserDetails searchUser(String username) {
|
||||
log.debug("LDAP 사용자 정보 조회 시작: username={}", username);
|
||||
|
||||
try {
|
||||
// uid로 사용자 검색
|
||||
Filter filter = new EqualsFilter("uid", username);
|
||||
|
||||
// 사용자 속성 조회
|
||||
List<LdapUserDetails> userList = ldapTemplate.search(
|
||||
userSearchBase,
|
||||
filter.encode(),
|
||||
new UserAttributesMapper(username)
|
||||
);
|
||||
|
||||
if (userList.isEmpty()) {
|
||||
log.warn("LDAP에서 사용자를 찾을 수 없음: username={}", username);
|
||||
// 사용자를 찾을 수 없어도 기본 정보로 생성
|
||||
return createDefaultUserDetails(username);
|
||||
}
|
||||
|
||||
return userList.get(0);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("LDAP 사용자 정보 조회 실패: username={}, error={}", username, e.getMessage(), e);
|
||||
// 오류 발생 시 기본 정보로 생성
|
||||
return createDefaultUserDetails(username);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 사용자 정보 생성 (LDAP 조회 실패 시)
|
||||
*
|
||||
* @param username 사용자 ID
|
||||
* @return 기본 사용자 정보
|
||||
*/
|
||||
private LdapUserDetails createDefaultUserDetails(String username) {
|
||||
return LdapUserDetails.builder()
|
||||
.userId(username)
|
||||
.username(username)
|
||||
.email(username + "@example.com")
|
||||
.department("미지정")
|
||||
.title("미지정")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* LDAP 속성을 LdapUserDetails로 매핑하는 Mapper
|
||||
*/
|
||||
private static class UserAttributesMapper implements AttributesMapper<LdapUserDetails> {
|
||||
private final String userId;
|
||||
|
||||
public UserAttributesMapper(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LdapUserDetails mapFromAttributes(Attributes attributes) throws NamingException {
|
||||
return LdapUserDetails.builder()
|
||||
.userId(userId)
|
||||
.username(getAttributeValue(attributes, "cn", userId))
|
||||
.email(getAttributeValue(attributes, "mail", userId + "@example.com"))
|
||||
.department(getAttributeValue(attributes, "department", "미지정"))
|
||||
.title(getAttributeValue(attributes, "title", "미지정"))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 속성 값 조회 (속성이 없으면 기본값 반환)
|
||||
*
|
||||
* @param attributes 속성 목록
|
||||
* @param attributeName 속성 이름
|
||||
* @param defaultValue 기본값
|
||||
* @return 속성 값
|
||||
*/
|
||||
private String getAttributeValue(Attributes attributes, String attributeName, String defaultValue) {
|
||||
try {
|
||||
if (attributes.get(attributeName) != null) {
|
||||
Object value = attributes.get(attributeName).get();
|
||||
return value != null ? value.toString() : defaultValue;
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
// 속성이 없거나 오류 발생 시 기본값 반환
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.unicorn.hgzero.user.config.ldap;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* LDAP에서 조회한 사용자 정보 DTO
|
||||
*
|
||||
* LDAP 인증 성공 후 사용자 속성 정보를 담는 클래스
|
||||
*/
|
||||
@Getter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LdapUserDetails {
|
||||
|
||||
/**
|
||||
* 사용자 ID (uid)
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 사용자 이름 (cn - Common Name)
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 이메일 (mail)
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 부서 (department)
|
||||
*/
|
||||
private String department;
|
||||
|
||||
/**
|
||||
* 직급 (title)
|
||||
*/
|
||||
private String title;
|
||||
}
|
||||
@ -138,4 +138,15 @@ public class UserEntity extends BaseTimeEntity {
|
||||
this.failedLoginAttempts = 0;
|
||||
this.lastLoginAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
/**
|
||||
* LDAP 정보로 사용자 정보 업데이트
|
||||
*
|
||||
* @param username 사용자 이름
|
||||
* @param email 이메일
|
||||
*/
|
||||
public void updateFromLdap(String username, String email) {
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package com.unicorn.hgzero.user.service;
|
||||
import com.unicorn.hgzero.common.exception.BusinessException;
|
||||
import com.unicorn.hgzero.common.exception.ErrorCode;
|
||||
import com.unicorn.hgzero.common.security.JwtTokenProvider;
|
||||
import com.unicorn.hgzero.user.config.ldap.LdapAuthenticator;
|
||||
import com.unicorn.hgzero.user.config.ldap.LdapUserDetails;
|
||||
import com.unicorn.hgzero.user.domain.User;
|
||||
import com.unicorn.hgzero.user.dto.*;
|
||||
import com.unicorn.hgzero.user.repository.entity.UserEntity;
|
||||
@ -37,7 +39,7 @@ import io.jsonwebtoken.security.Keys;
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
private final LdapTemplate ldapTemplate;
|
||||
private final LdapAuthenticator ldapAuthenticator;
|
||||
private final UserRepository userRepository;
|
||||
private final JwtTokenProvider jwtTokenProvider;
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
@ -64,7 +66,7 @@ public class UserServiceImpl implements UserService {
|
||||
public LoginResponse login(LoginRequest request) {
|
||||
log.info("로그인 시도: userId={}", request.getUserId());
|
||||
|
||||
// 사용자 조회 또는 생성
|
||||
// 사용자 조회
|
||||
UserEntity userEntity = userRepository.findById(request.getUserId())
|
||||
.orElse(null);
|
||||
|
||||
@ -81,10 +83,12 @@ public class UserServiceImpl implements UserService {
|
||||
}
|
||||
}
|
||||
|
||||
// LDAP 인증
|
||||
// LDAP 인증 및 사용자 정보 조회
|
||||
LdapUserDetails ldapUserDetails;
|
||||
try {
|
||||
authenticateWithLdap(request.getUserId(), request.getPassword());
|
||||
log.info("LDAP 인증 성공: userId={}", request.getUserId());
|
||||
ldapUserDetails = ldapAuthenticator.validateCredentials(request.getUserId(), request.getPassword());
|
||||
log.info("LDAP 인증 성공: userId={}, username={}, email={}",
|
||||
request.getUserId(), ldapUserDetails.getUsername(), ldapUserDetails.getEmail());
|
||||
} catch (Exception e) {
|
||||
log.error("LDAP 인증 실패: userId={}, error={}", request.getUserId(), e.getMessage());
|
||||
|
||||
@ -99,15 +103,26 @@ public class UserServiceImpl implements UserService {
|
||||
|
||||
// 사용자 정보 조회 또는 생성
|
||||
if (userEntity == null) {
|
||||
// LDAP에서 추가 정보 조회 (실제 환경에서는 LDAP에서 이메일 등을 가져와야 함)
|
||||
// LDAP에서 조회한 정보로 신규 사용자 등록
|
||||
log.info("신규 사용자 등록: userId={}, username={}, email={}, department={}, title={}",
|
||||
ldapUserDetails.getUserId(), ldapUserDetails.getUsername(),
|
||||
ldapUserDetails.getEmail(), ldapUserDetails.getDepartment(), ldapUserDetails.getTitle());
|
||||
|
||||
userEntity = UserEntity.builder()
|
||||
.userId(request.getUserId())
|
||||
.username(request.getUserId()) // LDAP에서 가져온 실제 이름 사용
|
||||
.email(request.getUserId() + "@example.com") // LDAP에서 가져온 실제 이메일 사용
|
||||
.userId(ldapUserDetails.getUserId())
|
||||
.username(ldapUserDetails.getUsername())
|
||||
.email(ldapUserDetails.getEmail())
|
||||
.authority("USER")
|
||||
.locked(false)
|
||||
.failedLoginAttempts(0)
|
||||
.build();
|
||||
} else {
|
||||
// 기존 사용자의 경우 LDAP 정보로 업데이트 (이메일, 이름 등이 변경될 수 있음)
|
||||
log.debug("기존 사용자 정보 업데이트: userId={}", request.getUserId());
|
||||
userEntity.updateFromLdap(
|
||||
ldapUserDetails.getUsername(),
|
||||
ldapUserDetails.getEmail()
|
||||
);
|
||||
}
|
||||
|
||||
// 로그인 성공 기록
|
||||
@ -124,7 +139,7 @@ public class UserServiceImpl implements UserService {
|
||||
saveRefreshToken(user.getUserId(), refreshToken);
|
||||
|
||||
log.info("로그인 성공: userId={}", request.getUserId());
|
||||
|
||||
|
||||
// 로그인 이벤트 발행
|
||||
eventPublishService.publishLoginEvent(user.getUserId(), user.getUsername(), System.currentTimeMillis());
|
||||
|
||||
@ -251,22 +266,6 @@ public class UserServiceImpl implements UserService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LDAP 인증 수행
|
||||
*/
|
||||
private void authenticateWithLdap(String userId, String password) {
|
||||
// LDAP DN 생성
|
||||
String userDn = userDnPattern.replace("{0}", userId);
|
||||
|
||||
// LDAP 인증
|
||||
Filter filter = new EqualsFilter("uid", userId);
|
||||
boolean authenticated = ldapTemplate.authenticate("", filter.encode(), password);
|
||||
|
||||
if (!authenticated) {
|
||||
throw new BusinessException(ErrorCode.AUTHENTICATION_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Token 생성
|
||||
*/
|
||||
|
||||
@ -8,7 +8,7 @@ spring:
|
||||
datasource:
|
||||
url: jdbc:${DB_KIND:postgresql}://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:userdb}
|
||||
username: ${DB_USERNAME:hgzerouser}
|
||||
password: ${DB_PASSWORD:Hi5Jessica!}
|
||||
password: ${DB_PASSWORD:}
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 20
|
||||
@ -27,7 +27,7 @@ spring:
|
||||
use_sql_comments: true
|
||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
||||
jdbc:
|
||||
time_zone: UTC
|
||||
time_zone: Asia/Seoul
|
||||
hibernate:
|
||||
ddl-auto: ${JPA_DDL_AUTO:update}
|
||||
database: postgresql
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user