Merge branch 'devs/ums' into jenkins_with_weblogic
This commit is contained in:
@@ -1,15 +0,0 @@
|
||||
package com.eactive.apim.portal.apps.app.mapper;
|
||||
|
||||
import com.eactive.apim.portal.app.entity.ProdClient;
|
||||
import com.eactive.apim.portal.apps.apiservice.mapper.ApiSpecInfoMapper;
|
||||
import com.eactive.apim.portal.apps.app.dto.ClientDTO;
|
||||
import com.eactive.eai.data.mapper.BaseMapperConfig;
|
||||
import com.eactive.eai.data.mapper.GenericMapper;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
@Mapper(config = BaseMapperConfig.class, uses = {ApiSpecInfoMapper.class})
|
||||
public interface ProdClientMapper extends GenericMapper<ClientDTO, ProdClient> {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -22,10 +22,10 @@ public class AuthNumberServiceImpl implements AuthNumberService {
|
||||
private final AuthNumberGenerator generator;
|
||||
private final MessageSender messageSender;
|
||||
|
||||
@Value("${auth-ttl:300}")
|
||||
@Value("${portal.auth-ttl:300}")
|
||||
private int authNumberExpirationTime;
|
||||
|
||||
@Value("${auth.resend.limit.seconds:30}")
|
||||
@Value("${portal.auth.resend_limit_seconds:30}")
|
||||
private int resendLimitSeconds;
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -46,6 +46,7 @@ public class AccountController {
|
||||
private final UserFacade userFacade;
|
||||
private final OrgRegisterFacade orgRegisterFacade;
|
||||
private final AgreementsFacade agreementsFacade;
|
||||
private final com.eactive.apim.portal.apps.user.facade.AuthFacade authFacade;
|
||||
|
||||
|
||||
@PostMapping("/confirm_password")
|
||||
@@ -326,4 +327,115 @@ public class AccountController {
|
||||
return "redirect:/mypage";
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/mypage/verification-email")
|
||||
public String showVerificationEmailPage(Model model) {
|
||||
try {
|
||||
// 현재 로그인한 사용자 정보 가져오기
|
||||
PortalAuthenticatedUser currentUser = SecurityUtil.getPortalAuthenticatedUser();
|
||||
|
||||
if (currentUser == null) {
|
||||
return "redirect:/login";
|
||||
}
|
||||
|
||||
// 사용자 이메일 주소를 모델에 추가
|
||||
model.addAttribute("email", currentUser.getUsername());
|
||||
model.addAttribute("userId", currentUser.getId());
|
||||
|
||||
return "apps/mypage/verificationEmail";
|
||||
} catch (Exception e) {
|
||||
logger.error("이메일 인증 페이지 로드 실패", e);
|
||||
return "redirect:/";
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/mypage/send-verification-code")
|
||||
public ResponseEntity<ValidationResponse> sendVerificationCode(
|
||||
@org.springframework.web.bind.annotation.RequestBody java.util.Map<String, String> request,
|
||||
HttpSession session) {
|
||||
try {
|
||||
String email = request.get("email");
|
||||
|
||||
// 현재 로그인한 사용자의 이메일과 일치하는지 확인
|
||||
PortalAuthenticatedUser currentUser = SecurityUtil.getPortalAuthenticatedUser();
|
||||
if (currentUser == null || !currentUser.getUsername().equals(email)) {
|
||||
ValidationResponse response = new ValidationResponse();
|
||||
response.setValid(false);
|
||||
response.setMessage("유효하지 않은 요청입니다.");
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
|
||||
// 이전 세션 데이터 정리
|
||||
session.removeAttribute("emailVerified");
|
||||
|
||||
// 이메일 인증 코드 발송
|
||||
ValidationResponse response = authFacade.requestAuth(email, "EMAIL");
|
||||
|
||||
if (response.isValid()) {
|
||||
session.setAttribute("verificationEmail", email);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("이메일 인증 코드 발송 실패", e);
|
||||
ValidationResponse response = new ValidationResponse();
|
||||
response.setValid(false);
|
||||
response.setMessage("인증 코드 발송에 실패했습니다.");
|
||||
return ResponseEntity.status(500).body(response);
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/mypage/verify-email-code")
|
||||
public ResponseEntity<ValidationResponse> verifyEmailCode(
|
||||
@org.springframework.web.bind.annotation.RequestBody java.util.Map<String, String> request,
|
||||
HttpSession session) {
|
||||
try {
|
||||
String email = request.get("email");
|
||||
String code = request.get("code");
|
||||
|
||||
// 현재 로그인한 사용자의 이메일과 일치하는지 확인
|
||||
PortalAuthenticatedUser currentUser = SecurityUtil.getPortalAuthenticatedUser();
|
||||
if (currentUser == null || !currentUser.getUsername().equals(email)) {
|
||||
ValidationResponse response = new ValidationResponse();
|
||||
response.setValid(false);
|
||||
response.setMessage("유효하지 않은 요청입니다.");
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
|
||||
// 세션에 저장된 이메일과 일치하는지 확인
|
||||
String sessionEmail = (String) session.getAttribute("verificationEmail");
|
||||
if (sessionEmail == null || !sessionEmail.equals(email)) {
|
||||
ValidationResponse response = new ValidationResponse();
|
||||
response.setValid(false);
|
||||
response.setMessage("인증 요청된 이메일과 일치하지 않습니다.");
|
||||
return ResponseEntity.badRequest().body(response);
|
||||
}
|
||||
|
||||
// 인증 코드 확인
|
||||
ValidationResponse response = authFacade.verifyAuthNumber(email, code);
|
||||
|
||||
if (response.isValid()) {
|
||||
session.setAttribute("emailVerified", true);
|
||||
|
||||
// 사용자 상태를 ACTIVE로 변경
|
||||
userFacade.activateUserByEmail(email);
|
||||
|
||||
// 이메일 인증 관련 세션 정보 제거
|
||||
session.removeAttribute("emailVerificationRequired");
|
||||
session.removeAttribute("redirectUrl");
|
||||
|
||||
logger.info("이메일 인증 완료: {}", email);
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("이메일 인증 코드 확인 실패", e);
|
||||
ValidationResponse response = new ValidationResponse();
|
||||
response.setValid(false);
|
||||
response.setMessage("인증 코드 확인에 실패했습니다.");
|
||||
return ResponseEntity.status(500).body(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,6 @@ public interface UserFacade {
|
||||
void updateCorporateManager(PortalUserDTO portalUserDTO);
|
||||
|
||||
void withdrawUser(String userId);
|
||||
|
||||
void activateUserByEmail(String email);
|
||||
}
|
||||
@@ -198,4 +198,23 @@ public class UserFacadeImpl implements UserFacade {
|
||||
throw new IllegalArgumentException("새 비밀번호와 확인 비밀번호가 일치하지 않습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void activateUserByEmail(String email) {
|
||||
PortalUser user = portalUserService.findByEmailAddr(email);
|
||||
|
||||
if (user == null) {
|
||||
throw new IllegalArgumentException("사용자를 찾을 수 없습니다.");
|
||||
}
|
||||
|
||||
if (user.getUserStatus() == PortalUserEnums.UserStatus.ACTIVE) {
|
||||
throw new IllegalArgumentException("이미 활성화된 계정입니다.");
|
||||
}
|
||||
|
||||
user.setUserStatus(PortalUserEnums.UserStatus.ACTIVE);
|
||||
portalUserService.save(user);
|
||||
|
||||
log.info("사용자 이메일 인증 완료 - 활성화: {}", email);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.eactive.apim.portal.common.util.SecurityUtil;
|
||||
import com.eactive.apim.portal.common.util.StringMaskingUtil;
|
||||
import com.eactive.apim.portal.invitation.entity.UserInvitation;
|
||||
import com.eactive.apim.portal.invitation.entity.UserInvitationEnums.InvitationStatus;
|
||||
import com.eactive.apim.portal.invitation.event.UserInvitationCancelEvent;
|
||||
import com.eactive.apim.portal.invitation.event.UserInvitationEvent;
|
||||
import com.eactive.apim.portal.portaluser.event.UserManagerAssignedEvent;
|
||||
import com.eactive.apim.portal.invitation.repository.UserInvitationRepository;
|
||||
@@ -183,7 +184,29 @@ public class UserManFacade {
|
||||
throw new IllegalStateException("Invitation is not in a cancelable state");
|
||||
}
|
||||
|
||||
// invitationId 로 사용자 이름 조회, 실패시 id 를 이름으로 대체
|
||||
String name = portalUserRepository.findById(invitation.getInvitationEmail())
|
||||
.map(PortalUser::getUserName)
|
||||
.orElse(invitation.getInvitationEmail());
|
||||
|
||||
// name 이 이메일 일 경우 @ 앞부분 만 사용 (안하면 암호화 해야함...)
|
||||
if (name.contains("@")) {
|
||||
name = name.substring(0, name.indexOf("@"));
|
||||
}
|
||||
|
||||
invitation.setStatus(InvitationStatus.CANCELED);
|
||||
|
||||
messageHandlerService.publishEvent(UserInvitationCancelEvent.KEY,
|
||||
MessageRecipient.builder()
|
||||
.username(name)
|
||||
.userId(invitationId)
|
||||
.build(),
|
||||
new HashMap<String, Object>() {{
|
||||
put("corpName", user.getPortalOrg().getOrgName());
|
||||
put("managerName", user.getUserName());
|
||||
}}
|
||||
);
|
||||
|
||||
userInvitationRepository.save(invitation);
|
||||
|
||||
}
|
||||
|
||||
@@ -146,7 +146,8 @@ public class UserRegisterFacadeImpl implements UserRegisterFacade {
|
||||
}
|
||||
|
||||
agreementsFacade.saveUserAgreements(newUser.getId(), AgreementType.PRIVACY_COLLECT_IND);
|
||||
sendEmailActivation(newUser);
|
||||
// 11.13 - 회원 가입단계가 아닌 로그인 단계로 이메일 인증 이동
|
||||
// sendEmailActivation(newUser);
|
||||
return new ValidationResponse(true,"회원가입이 완료되었습니다.");
|
||||
}
|
||||
|
||||
|
||||
@@ -96,9 +96,10 @@ public class PortalUserAuthService implements UserDetailsService {
|
||||
|
||||
public void initializePassword(String loginId, String userName, String mobileNumber) {
|
||||
|
||||
PortalUser portalUser = portalUserRepository.findByLoginIdAndUserNameAndMobileNumber(loginId, userName, mobileNumber).orElseThrow(() -> new UserNotFoundException("일치하는 사용자 정보를 찾을 수 없습니다."));
|
||||
PortalUser portalUser = portalUserRepository.findByLoginIdAndUserNameAndMobileNumber(loginId, userName, mobileNumber)
|
||||
.orElseThrow(() -> new UserNotFoundException("일치하는 사용자 정보를 찾을 수 없습니다."));
|
||||
|
||||
String tempPassword = EncryptionUtil.generateNewPassword();
|
||||
String tempPassword = EncryptionUtil.generateNewPasswordForKjbank(loginId);
|
||||
portalUser.setPasswordHash(passwordEncoder.encode(tempPassword));
|
||||
|
||||
portalUserRepository.save(portalUser);
|
||||
|
||||
@@ -49,6 +49,15 @@ public class PortalUserService {
|
||||
return portalUserRepository.findByLoginId(loginId);
|
||||
}
|
||||
|
||||
public PortalUser findByEmailAddr(String emailAddr) {
|
||||
return portalUserRepository.findPortalUserByEmailAddr(emailAddr)
|
||||
.orElseThrow(() -> new IllegalArgumentException("해당 이메일 주소의 사용자를 찾을 수 없습니다."));
|
||||
}
|
||||
|
||||
public PortalUser save(PortalUser user) {
|
||||
return portalUserRepository.save(user);
|
||||
}
|
||||
|
||||
public boolean existsByLoginId(String loginId) {
|
||||
return portalUserRepository.existsByLoginId(loginId);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,30 @@ public class EncryptionUtil {
|
||||
return newpassword.toString();
|
||||
}
|
||||
|
||||
@Value("${encryption.key:kbank_portal_application_1357902}")
|
||||
/**
|
||||
* 광주은행용 임시패스워드 생성
|
||||
* - @ + 이메일 주소 앞 5자리 + 랜덤숫자 3자리 + !
|
||||
* @return
|
||||
*/
|
||||
public static String generateNewPasswordForKjbank(String loginId) {
|
||||
StringBuilder newpassword = new StringBuilder();
|
||||
newpassword.append("@");
|
||||
|
||||
if (loginId.length() <= 5) {
|
||||
newpassword.append(loginId);
|
||||
} else {
|
||||
newpassword.append(loginId.substring(0, 5));
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
newpassword.append(RandomUtil.getRandomNum(0, 9));
|
||||
}
|
||||
newpassword.append("!");
|
||||
|
||||
return newpassword.toString();
|
||||
}
|
||||
|
||||
@Value("${encryption.key:kjbank_portal_application_1357902}")
|
||||
private String secretKey; // Should be 16, 24, or 32 bytes long for AES-128, AES-192, or AES-256
|
||||
|
||||
private static final String ALGORITHM = "AES";
|
||||
|
||||
+24
-6
@@ -5,11 +5,10 @@ import com.eactive.apim.portal.apps.user.service.PortalUserLogService;
|
||||
import com.eactive.apim.portal.common.exception.UserNotFoundException;
|
||||
import com.eactive.apim.portal.portaluser.entity.PortalUser;
|
||||
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.service.MessageHandlerService;
|
||||
import com.eactive.apim.portal.template.service.MessageRecipient;
|
||||
import org.apache.groovy.util.Maps;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -20,6 +19,11 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Sungpil Hyun
|
||||
*/
|
||||
@@ -30,10 +34,15 @@ public class PortalAuthenticationFailureHandler implements AuthenticationFailure
|
||||
private static final Logger logger = LoggerFactory.getLogger(PortalAuthenticationFailureHandler.class);
|
||||
private final PortalUserRepository portalUserRepository;
|
||||
private final PortalUserLogService userLogService;
|
||||
private final MessageHandlerService messageHandlerService;
|
||||
|
||||
public PortalAuthenticationFailureHandler(PortalUserRepository portalUserRepository, PortalUserLogService userLogService) {
|
||||
|
||||
public PortalAuthenticationFailureHandler(PortalUserRepository portalUserRepository,
|
||||
PortalUserLogService userLogService,
|
||||
MessageHandlerService messageHandlerService) {
|
||||
this.portalUserRepository = portalUserRepository;
|
||||
this.userLogService = userLogService;
|
||||
this.messageHandlerService = messageHandlerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,8 +62,17 @@ public class PortalAuthenticationFailureHandler implements AuthenticationFailure
|
||||
user.setLoginFailureCount(user.getLoginFailureCount() + 1);
|
||||
if (user.getLoginFailureCount() >= 5) {
|
||||
user.setAccountLockYn("Y");
|
||||
|
||||
// 계정 잠금 알림
|
||||
messageHandlerService.publishEvent(
|
||||
MessageCode.USER_ACCOUNT_LOCKED,
|
||||
MessageRecipient.of(user),
|
||||
Maps.of("reason", "5회 이상 로그인 실패로 인한 계정 잠금")) ;;
|
||||
}
|
||||
portalUserRepository.save(user);
|
||||
|
||||
|
||||
|
||||
} catch (UserNotFoundException e) {
|
||||
logger.error("{} login try {}", username, e.getMessage());
|
||||
}
|
||||
|
||||
@@ -5,8 +5,12 @@ import com.eactive.apim.portal.apps.user.service.PortalUserAuthService;
|
||||
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
|
||||
import com.eactive.apim.portal.portalorg.entity.PortalOrgEnums;
|
||||
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.service.MessageHandlerService;
|
||||
import com.eactive.apim.portal.template.service.MessageRecipient;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.groovy.util.Maps;
|
||||
import org.springframework.security.authentication.*;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -25,6 +29,7 @@ public class PortalAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
private final PortalUserAuthService portalUserAuthService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final MessageHandlerService messageHandlerService;
|
||||
|
||||
private String decodePassword(String encodedPassword) {
|
||||
try {
|
||||
@@ -46,6 +51,16 @@ public class PortalAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
PortalAuthenticatedUser user = (PortalAuthenticatedUser) portalUserAuthService.loadUserByUsername(username);
|
||||
|
||||
|
||||
if (!user.isAccountNonLocked()) {
|
||||
if (user.getLoginFailureCount() >= 5) {
|
||||
throw new LockedException("계정이 잠겼습니다. 비밀번호 초기화 또는 관리자에게 문의하세요.");
|
||||
}
|
||||
|
||||
throw new LockedException("로그인 할 수 없습니다. 비밀번호 초기화 또는 관리자에게 문의하세요.");
|
||||
}
|
||||
|
||||
|
||||
// 비밀번호 검증
|
||||
if (!passwordEncoder.matches(decodedPassword, user.getPassword())) {
|
||||
// 암호화가 되어 있지 않을 수도 있어 그대로 비교 검증
|
||||
@@ -67,9 +82,10 @@ public class PortalAuthenticationManager implements AuthenticationManager {
|
||||
throw new DisabledException("사용자 승인 대기중입니다. ");
|
||||
}
|
||||
|
||||
if (user.getUserStatus().equals(PortalUserEnums.UserStatus.READY)) {
|
||||
throw new DisabledException("이메일 인증이 완료되지 않았습니다. 인증 메일을 확인해주세요.");
|
||||
}
|
||||
// 25.11.13 - 이메일 인증 로그인은 허용
|
||||
// if (user.getUserStatus().equals(PortalUserEnums.UserStatus.READY)) {
|
||||
// throw new DisabledException("이메일 인증이 완료되지 않았습니다. 인증 메일을 확인해주세요.");
|
||||
// }
|
||||
|
||||
if (user.getUserStatus().equals(PortalUserEnums.UserStatus.ADMINBLOCK)) {
|
||||
throw new DisabledException("법인 관리자에 의해 비활성화된 계정입니다. 법인 관리자에게 문의하시기 바랍니다.");
|
||||
@@ -82,9 +98,7 @@ public class PortalAuthenticationManager implements AuthenticationManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (!user.isAccountNonLocked()) {
|
||||
throw new LockedException("로그인 할 수 없습니다. 비밀번호 초기화 또는 관리자에게 문의하세요.");
|
||||
}
|
||||
|
||||
|
||||
UsernamePasswordAuthenticationToken authorityToken =
|
||||
new UsernamePasswordAuthenticationToken(user, decodedPassword, user.getAuthorities());
|
||||
|
||||
+9
-1
@@ -55,7 +55,11 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
// 세션에 상태 저장
|
||||
if (isDormantAccount(user)) {
|
||||
if (isEmailVerificationRequired(user)) {
|
||||
session.setAttribute("success", "이메일 인증이 완료되지 않았습니다. 이메일을 확인하여 인증을 완료해주세요.");
|
||||
session.setAttribute("emailVerificationRequired", true);
|
||||
session.setAttribute("redirectUrl", contextPath + "/mypage/verification-email");
|
||||
} else if (isDormantAccount(user)) {
|
||||
session.setAttribute("success", "90일 이상 미접속하여 계정이 잠금 처리되었습니다. 본인인증 후 이용해주세요.");
|
||||
session.setAttribute("dormantAccount", true);
|
||||
session.setAttribute("dormantLoginId", username);
|
||||
@@ -114,4 +118,8 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
|
||||
return PortalUserEnums.UserStatus.DORMANT.equals(user.getUserStatus());
|
||||
}
|
||||
|
||||
private boolean isEmailVerificationRequired(PortalUser user) {
|
||||
return PortalUserEnums.UserStatus.READY.equals(user.getUserStatus());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ portal:
|
||||
log-path: /Log/App/eapim/
|
||||
|
||||
auth-ttl: 300
|
||||
auth:
|
||||
resend_limit_seconds: 30
|
||||
|
||||
user-approval: true
|
||||
password-expiration-days: 90
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
|
||||
|
||||
<logger name="com.eactive.apim" level="DEBUG" />
|
||||
<logger name="org.thymeleaf.templateparser" level="DEBUG" />
|
||||
|
||||
|
||||
<!-- Hibernate SQL Logging -->
|
||||
|
||||
@@ -163,7 +163,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const sub = document.getElementById('sub');
|
||||
|
||||
// 초기에 서브 메뉴 숨기기
|
||||
sub.style.display = 'none';
|
||||
if (sub == null) {
|
||||
sub.style.display = 'none';
|
||||
}
|
||||
|
||||
// 마우스가 메인 네비게이션에 진입했을 때
|
||||
mainNav.addEventListener('mouseenter', function() {
|
||||
|
||||
@@ -145,10 +145,10 @@
|
||||
}
|
||||
if (document.loginForm.message && document.loginForm.message.value) {
|
||||
if (document.loginForm.message.value.includes("이메일 인증이 완료되지 않았습니다")) {
|
||||
console.log("이메일 재발송 팝업 트리거");
|
||||
let loginId = $('#loginId').val();
|
||||
console.log("Retrieved loginId:", loginId);
|
||||
customPopups.showEmailResendPopup(document.loginForm.message.value, loginId);
|
||||
console.log("이메일 인증 페이지 이동");
|
||||
location.href = '/mypage/verification-email'
|
||||
// console.log("Retrieved loginId:", loginId);
|
||||
// customPopups.showEmailResendPopup(document.loginForm.message.value, loginId);
|
||||
} else {
|
||||
customPopups.showAlert(document.loginForm.message.value);
|
||||
}
|
||||
|
||||
@@ -248,6 +248,23 @@
|
||||
customPopups.showAlert(successMsg);
|
||||
}
|
||||
|
||||
// 이메일 인증 체크
|
||||
const emailVerificationRequired = [[${session.emailVerificationRequired}]];
|
||||
if (emailVerificationRequired) {
|
||||
const emailVerifyMsg = /*[[${session.success}]]*/ '';
|
||||
const redirectUrl = /*[[${session.redirectUrl}]]*/ '';
|
||||
|
||||
console.log('emailVerifyMsg:', emailVerifyMsg);
|
||||
console.log('redirectUrl:', redirectUrl);
|
||||
|
||||
customPopups.showAlert(emailVerifyMsg);
|
||||
$('#customAlertOkButton').off('click.custom').on('click.custom', function () {
|
||||
customPopups.hideAlert('#customAlert');
|
||||
window.location.href = redirectUrl;
|
||||
});
|
||||
return; // 다른 체크 중단
|
||||
}
|
||||
|
||||
// 장기미사용 계정 체크
|
||||
const dormantAccount = [[${session.dormantAccount}]];
|
||||
if (dormantAccount) {
|
||||
@@ -428,7 +445,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
G
|
||||
const hashtagItems = document.querySelectorAll('.hashtag ul li a');
|
||||
const searchBox = document.getElementById('search-box');
|
||||
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/kbank_base_layout}">
|
||||
<body>
|
||||
<section layout:fragment="contentFragment" class="content">
|
||||
<div class="content_wrap">
|
||||
<!-- 타이틀 -->
|
||||
<div class="sub_title2" id="title-verification-email">
|
||||
<h2 class="title add5">이메일 인증</h2>
|
||||
</div>
|
||||
|
||||
<div class="inner i_cs10 h_inner2">
|
||||
|
||||
<div class="form_type">
|
||||
<form id="verificationEmailForm" role="form" name="verificationEmailForm" method="post">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<input type="hidden" id="userId" name="userId" th:value="${userId}">
|
||||
|
||||
<!-- 이메일 주소 표시 (readonly) -->
|
||||
<div class="info1 p_top2">
|
||||
<p class="title w_tit">
|
||||
<span class="dot">이메일 주소</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1 w_inp4">
|
||||
<input type="email" id="email" name="email" class="common_input_type_1"
|
||||
th:value="${email}" readonly style="background-color: #f5f5f5;">
|
||||
</div>
|
||||
</div>
|
||||
<p class="info_txt" style="margin-top: 10px; color: #666;">
|
||||
위 이메일 주소로 인증코드가 발송됩니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 인증코드 받기 버튼 -->
|
||||
<div class="info1 pt28">
|
||||
<div class="btn_check" style="width: 100%;">
|
||||
<a class="common_btn_type_2 cbt btn_send_code" style="width: 100%;"><span>인증코드 받기</span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 인증번호 입력 -->
|
||||
<div class="info1 pt28 auth-code-container" id="authCodeContainer" style="display: none;">
|
||||
<p class="title w_tit">
|
||||
<span class="dot">인증코드 입력</span>
|
||||
</p>
|
||||
<div class="info_line">
|
||||
<div class="info_box1 w_inp5">
|
||||
<div class="certify_box">
|
||||
<input type="text" id="authCode" class="common_input_type_1 w_input"
|
||||
placeholder="이메일로 받은 인증코드를 입력하세요" maxlength="6" required>
|
||||
<span class="certify_time" id="certify_time">05:00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn_check">
|
||||
<a class="common_btn_type_2 cbt btn_verify_code"><span>인증코드 확인</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 제출 버튼 -->
|
||||
<div class="btn_application m_top">
|
||||
<a type="button" class="common_btn_type_1 gray btn_cancel"><span>취소</span></a>
|
||||
<!-- <div class="btn_gap"></div>-->
|
||||
<!-- <button type="button" class="common_btn_type_1 btn_complete" disabled><span>인증 완료</span></button>-->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script th:inline="javascript">
|
||||
$(document).ready(function() {
|
||||
let timerInterval;
|
||||
let resendTimerInterval;
|
||||
let isVerified = false;
|
||||
|
||||
// CSRF 토큰 설정
|
||||
const csrfHeaderName = /*[[${_csrf.headerName}]]*/ 'X-CSRF-TOKEN';
|
||||
const csrfToken = /*[[${_csrf.token}]]*/ '';
|
||||
|
||||
// 서버 설정값
|
||||
const resendLimitSeconds = /*[[${@environment.getProperty('portal.auth.resend_limit_seconds', '60')}]]*/ 60;
|
||||
|
||||
// 취소 버튼 클릭 시 메인 페이지로 이동
|
||||
$('.btn_cancel').on('click', function() {
|
||||
if (confirm('이메일 인증을 취소하고 메인 페이지로 이동하시겠습니까?')) {
|
||||
location.href = '/';
|
||||
}
|
||||
});
|
||||
|
||||
// 타이머 시작 함수 (인증 코드 유효 시간)
|
||||
function startTimer(duration) {
|
||||
let timer = duration;
|
||||
clearInterval(timerInterval);
|
||||
|
||||
timerInterval = setInterval(function () {
|
||||
let minutes = parseInt(timer / 60, 10);
|
||||
let seconds = parseInt(timer % 60, 10);
|
||||
|
||||
minutes = minutes < 10 ? "0" + minutes : minutes;
|
||||
seconds = seconds < 10 ? "0" + seconds : seconds;
|
||||
|
||||
$('#certify_time').text(minutes + ":" + seconds);
|
||||
|
||||
if (--timer < 0) {
|
||||
clearInterval(timerInterval);
|
||||
$('#certify_time').text("00:00").css('color', 'red');
|
||||
customPopups.showAlert("인증 시간이 만료되었습니다. 인증코드를 다시 받아주세요.");
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 재발송 타이머 시작 함수
|
||||
function startResendTimer() {
|
||||
let resendTimer = resendLimitSeconds;
|
||||
const $button = $('.btn_send_code');
|
||||
|
||||
clearInterval(resendTimerInterval);
|
||||
$button.prop('disabled', true);
|
||||
|
||||
resendTimerInterval = setInterval(function () {
|
||||
if (resendTimer > 0) {
|
||||
$button.find('span').text('재발송 가능 (' + resendTimer + '초)');
|
||||
resendTimer--;
|
||||
} else {
|
||||
clearInterval(resendTimerInterval);
|
||||
$button.prop('disabled', false).find('span').text('인증코드 재발송');
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 인증코드 받기 버튼 클릭
|
||||
$('.btn_send_code').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const email = $('#email').val();
|
||||
const $button = $(this);
|
||||
|
||||
$button.prop('disabled', true).find('span').text('발송 중...');
|
||||
|
||||
$.ajax({
|
||||
url: '/mypage/send-verification-code',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ email: email }),
|
||||
headers: {
|
||||
[csrfHeaderName]: csrfToken
|
||||
},
|
||||
success: function(response) {
|
||||
customPopups.showAlert('인증코드가 이메일로 발송되었습니다.');
|
||||
$('#authCodeContainer').show();
|
||||
startTimer(300); // 5분 타이머
|
||||
startResendTimer(); // 재발송 타이머 시작 (1분)
|
||||
},
|
||||
error: function(xhr) {
|
||||
const errorMsg = xhr.responseJSON?.error || '인증코드 발송에 실패했습니다.';
|
||||
customPopups.showAlert(errorMsg);
|
||||
$button.prop('disabled', false).find('span').text('인증코드 받기');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 인증코드 확인 버튼 클릭
|
||||
$('.btn_verify_code').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const authCode = $('#authCode').val().trim();
|
||||
const email = $('#email').val();
|
||||
|
||||
if (!authCode) {
|
||||
customPopups.showAlert('인증코드를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (authCode.length !== 6) {
|
||||
customPopups.showAlert('6자리 인증코드를 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/mypage/verify-email-code',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({
|
||||
email: email,
|
||||
code: authCode
|
||||
}),
|
||||
headers: {
|
||||
[csrfHeaderName]: csrfToken
|
||||
},
|
||||
success: function(response) {
|
||||
clearInterval(timerInterval);
|
||||
isVerified = true;
|
||||
customPopups.showAlert('이메일 인증이 완료되었습니다!');
|
||||
|
||||
// 알림 확인 후 메인 페이지로 이동
|
||||
$('#customAlertOkButton').off('click.emailVerify').on('click.emailVerify', function () {
|
||||
customPopups.hideAlert('#customAlert');
|
||||
location.href = '/';
|
||||
});
|
||||
},
|
||||
error: function(xhr) {
|
||||
const errorMsg = xhr.responseJSON?.error || '인증코드가 일치하지 않습니다.';
|
||||
customPopups.showAlert(errorMsg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 인증 완료 버튼 클릭
|
||||
$('.btn_complete').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!isVerified) {
|
||||
customPopups.showAlert('이메일 인증을 먼저 완료해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 메인 페이지로 이동
|
||||
customPopups.showAlert('이메일 인증이 완료되었습니다. 메인 페이지로 이동합니다.');
|
||||
setTimeout(function() {
|
||||
location.href = '/';
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</th:block>
|
||||
</html>
|
||||
Reference in New Issue
Block a user