diff --git a/src/main/java/kr/co/hconnect/common/ApiResponseCode.java b/src/main/java/kr/co/hconnect/common/ApiResponseCode.java index 2d26bc7..cbaf076 100644 --- a/src/main/java/kr/co/hconnect/common/ApiResponseCode.java +++ b/src/main/java/kr/co/hconnect/common/ApiResponseCode.java @@ -29,6 +29,10 @@ public enum ApiResponseCode { * 격리상태 내역이 존재하지 않는 경우 */ NOT_FOUND_QUARANTINE_INFO("14"), + /** + * 사용자 정보가 존재하지 않는 경우 + */ + NOT_FOUND_USER_INFO("15"), /** * 내원중인 격리/입소내역이 존재하지 않는 경우 diff --git a/src/main/java/kr/co/hconnect/controller/LoginController.java b/src/main/java/kr/co/hconnect/controller/LoginController.java index 9a4a03b..234226e 100644 --- a/src/main/java/kr/co/hconnect/controller/LoginController.java +++ b/src/main/java/kr/co/hconnect/controller/LoginController.java @@ -1,8 +1,6 @@ package kr.co.hconnect.controller; import kr.co.hconnect.service.UserService; -import kr.co.hconnect.vo.LoginVO; -import kr.co.hconnect.vo.SessionVO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -14,6 +12,7 @@ /** * 로그인 컨트롤러 */ +@Deprecated @Controller @RequestMapping("/login") public class LoginController { @@ -48,20 +47,21 @@ public ModelAndView checkLogin(@RequestParam(value = "userId") String userId , @RequestParam(value = "password") String password , HttpServletRequest request) { - // 로그인 정보 조회 - LoginVO loginVO = service.selectLoginInfo(userId, password); - - // 로그인 사용자 정보 세션에 설정 - if (loginVO.getUserVO() != null) { - SessionVO sessionVO = new SessionVO(); - sessionVO.setUserId(loginVO.getUserVO().getUserId()); - sessionVO.setUserNm(loginVO.getUserVO().getUserNm()); - sessionVO.setCenterId(loginVO.getUserVO().getCenterId()); - request.getSession().setAttribute("sessionVO", sessionVO); - } - +// // 로그인 정보 조회 +// LoginVO loginVO = service.selectLoginInfo(userId, password); +// +// // 로그인 사용자 정보 세션에 설정 +// if (loginVO.getUserVO() != null) { +// SessionVO sessionVO = new SessionVO(); +// sessionVO.setUserId(loginVO.getUserVO().getUserId()); +// sessionVO.setUserNm(loginVO.getUserVO().getUserNm()); +// sessionVO.setCenterId(loginVO.getUserVO().getCenterId()); +// request.getSession().setAttribute("sessionVO", sessionVO); +// } +// ModelAndView mv = new ModelAndView("jsonView"); - mv.addObject("loginFailMessage", loginVO.getFailMessage()); // 로그인 실패 사유 +// mv.addObject("loginFailMessage", loginVO.getFailMessage()); // 로그인 실패 사유 + mv.addObject("loginFailMessage", ""); // 로그인 실패 사유 return mv; } diff --git a/src/main/java/kr/co/hconnect/domain/UserLoginInfo.java b/src/main/java/kr/co/hconnect/domain/UserLoginInfo.java new file mode 100644 index 0000000..3e40749 --- /dev/null +++ b/src/main/java/kr/co/hconnect/domain/UserLoginInfo.java @@ -0,0 +1,42 @@ +package kr.co.hconnect.domain; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * 사용자 로그인 정보 + */ +@Getter +@Setter +@NoArgsConstructor +@ToString +public class UserLoginInfo implements Serializable { + + private static final long serialVersionUID = -1773620410222057699L; + + /** + * 아이디 + */ + @NotNull(message = "{validation.null.loginId}") + private String loginId; + + /** + * 비밀번호 + */ + @NotNull(message = "{validation.null.password}") + @Size(max = 20, message = "{validation.size.password}") + private String password; + + /** + * 로그인 유지 여부 + */ + @Pattern(regexp = "^[YN]$") + private String rememberYn; +} diff --git a/src/main/java/kr/co/hconnect/domain/UserLoginResponse.java b/src/main/java/kr/co/hconnect/domain/UserLoginResponse.java new file mode 100644 index 0000000..8596f47 --- /dev/null +++ b/src/main/java/kr/co/hconnect/domain/UserLoginResponse.java @@ -0,0 +1,23 @@ +package kr.co.hconnect.domain; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * 로그인 응답 정보 + */ +@Getter +@Setter +@NoArgsConstructor +@ToString +public class UserLoginResponse extends BaseResponse { + + private static final long serialVersionUID = -2461380484928982120L; + + /** + * AccessToken + */ + private String token; +} diff --git a/src/main/java/kr/co/hconnect/exception/NotFoundUserInfoException.java b/src/main/java/kr/co/hconnect/exception/NotFoundUserInfoException.java new file mode 100644 index 0000000..e33150d --- /dev/null +++ b/src/main/java/kr/co/hconnect/exception/NotFoundUserInfoException.java @@ -0,0 +1,23 @@ +package kr.co.hconnect.exception; + +/** + * 사용자 정보 미존재 Exception + */ +public class NotFoundUserInfoException extends RuntimeException { + + private static final long serialVersionUID = 2009383189724700722L; + + /** + * 오류 내역 + */ + private final String errorMessage; + + public NotFoundUserInfoException(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public String getMessage() { + return errorMessage; + } +} diff --git a/src/main/java/kr/co/hconnect/jwt/TokenProvider.java b/src/main/java/kr/co/hconnect/jwt/TokenProvider.java index 1ea63e7..4c642e8 100644 --- a/src/main/java/kr/co/hconnect/jwt/TokenProvider.java +++ b/src/main/java/kr/co/hconnect/jwt/TokenProvider.java @@ -2,6 +2,7 @@ import io.jsonwebtoken.*; import kr.co.hconnect.common.TokenStatus; +import kr.co.hconnect.vo.UserVO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -60,9 +61,32 @@ public String createToken() { .setIssuedAt(now) // 발급시간 .setExpiration(validityInterval) // 만료시간 .signWith(key, keyAlg) // 키정보 및 해싱 알고리즘 정보 + .claim("tokenType", "app") .compact(); } + /** + * web 사용자 토큰 생성 + * + * @return 토큰 정보 + */ + public String createUserToken(UserVO userVO) { + Date now = new Date(); + // 토큰 만료시간 + Date validityInterval = new Date(now.getTime() + this.validity); + + return Jwts.builder() + .setHeaderParam(Header.TYPE, Header.JWT_TYPE) // 헤더 타입 지정 + .setIssuer("HealthConnect") // 발급자 정보 + .setIssuedAt(now) // 발급시간 + .setExpiration(validityInterval) // 만료시간 + .signWith(key, keyAlg) // 키정보 및 해싱 알고리즘 정보 + .claim("tokenType", "web") + .claim("userId", userVO.getUserId()) + .claim("userNm", userVO.getUserNm()) + .compact(); + } + /** * 토큰 유효성 확인 * diff --git a/src/main/java/kr/co/hconnect/repository/UserDao.java b/src/main/java/kr/co/hconnect/repository/UserDao.java index a80419f..bf2a2b8 100644 --- a/src/main/java/kr/co/hconnect/repository/UserDao.java +++ b/src/main/java/kr/co/hconnect/repository/UserDao.java @@ -45,6 +45,14 @@ public void updateUser(UserVO vo) { update("kr.co.hconnect.sqlmapper.updateUser",vo); } + /** + * 로그인 정보 업데이트 + * @param vo UserVO + */ + public void updateUserLoginInfo(UserVO vo) { + update("kr.co.hconnect.sqlmapper.updateUserLoginInfo", vo); + } + /** *유저정보 삭제 * @param userId 유저Id diff --git a/src/main/java/kr/co/hconnect/rest/UserLoginRestController.java b/src/main/java/kr/co/hconnect/rest/UserLoginRestController.java new file mode 100644 index 0000000..751d86c --- /dev/null +++ b/src/main/java/kr/co/hconnect/rest/UserLoginRestController.java @@ -0,0 +1,79 @@ +package kr.co.hconnect.rest; + +import kr.co.hconnect.common.ApiResponseCode; +import kr.co.hconnect.domain.UserLoginInfo; +import kr.co.hconnect.domain.UserLoginResponse; +import kr.co.hconnect.exception.InvalidRequestArgumentException; +import kr.co.hconnect.exception.NotFoundUserInfoException; +import kr.co.hconnect.exception.NotMatchPatientPasswordException; +import kr.co.hconnect.jwt.TokenProvider; +import kr.co.hconnect.service.UserService; +import kr.co.hconnect.vo.UserVO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@CrossOrigin +@RestController +@RequestMapping("/api") +public class UserLoginRestController { + + private static final Logger LOGGER = LoggerFactory.getLogger(UserLoginRestController.class); + + private final TokenProvider tokenProvider; + + /** + * 사용자 서비스 + */ + private final UserService userService; + + /** + * 생성자 + * @param tokenProvider Token 관리 + * @param userService 사용자 서비스 + */ + public UserLoginRestController(TokenProvider tokenProvider, UserService userService) { + this.tokenProvider = tokenProvider; + this.userService = userService; + } + + /** + * 로그인 정보 확인 + */ + @RequestMapping(value="/userLogin", method = RequestMethod.POST) + public UserLoginResponse checkLogin(@Valid @RequestBody UserLoginInfo userLoginInfo, BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + throw new InvalidRequestArgumentException(bindingResult); + } + + UserLoginResponse userLoginResponse = new UserLoginResponse(); + + try { + // 로그인 정보 조회 + UserVO userVO = userService.selectLoginInfo(userLoginInfo); + + // 사용자 로그인 정보 업데이트 + userVO.setRememberYn(userLoginInfo.getRememberYn()); + userService.updateUserLoginInfo(userVO); + + // Token 발행 + String token = tokenProvider.createUserToken(userVO); + + userLoginResponse.setCode(ApiResponseCode.SUCCESS.getCode()); + userLoginResponse.setMessage("로그인 성공"); + userLoginResponse.setToken(token); + } catch (NotFoundUserInfoException e) { + userLoginResponse.setCode(ApiResponseCode.NOT_FOUND_USER_INFO.getCode()); + userLoginResponse.setMessage(e.getMessage()); + } catch (NotMatchPatientPasswordException e) { + userLoginResponse.setCode(ApiResponseCode.NOT_MATCH_PATIENT_PASSWORD.getCode()); + userLoginResponse.setMessage(e.getMessage()); + } + + return userLoginResponse; + } + +} diff --git a/src/main/java/kr/co/hconnect/service/UserService.java b/src/main/java/kr/co/hconnect/service/UserService.java index 3fb40e7..38c5fa2 100644 --- a/src/main/java/kr/co/hconnect/service/UserService.java +++ b/src/main/java/kr/co/hconnect/service/UserService.java @@ -4,17 +4,21 @@ import egovframework.rte.fdl.cmmn.exception.FdlException; import egovframework.rte.fdl.idgnr.EgovIdGnrService; import kr.co.hconnect.common.CryptoUtils; +import kr.co.hconnect.domain.UserLoginInfo; +import kr.co.hconnect.exception.NotFoundUserInfoException; +import kr.co.hconnect.exception.NotMatchPatientPasswordException; import kr.co.hconnect.repository.UserDao; -import kr.co.hconnect.vo.LoginVO; import kr.co.hconnect.vo.UserVO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.MessageSource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Locale; /** * 사용자 서비스 @@ -25,18 +29,30 @@ public class UserService extends EgovAbstractServiceImpl { private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class); - private final UserDao userDao; // 사용자 Dao - private final EgovIdGnrService userIdGnrService; // 사용자ID 채번 서비스 + /** + * 사용자 Dao + */ + private final UserDao userDao; + /** + * 사용자ID 채번 서비스 + */ + private final EgovIdGnrService userIdGnrService; + /** + * MessageSource + */ + private final MessageSource messageSource; /** * 생성자 * @param userDao 사용자 Dao * @param userIdGnrService 사용자ID 채번 서비스 + * @param messageSource MessageSource */ @Autowired - public UserService(UserDao userDao, @Qualifier("userIdGnrService") EgovIdGnrService userIdGnrService) { + public UserService(UserDao userDao, @Qualifier("userIdGnrService") EgovIdGnrService userIdGnrService, MessageSource messageSource) { this.userDao = userDao; this.userIdGnrService = userIdGnrService; + this.messageSource = messageSource; } /** @@ -52,30 +68,27 @@ public UserVO selectUserInfo(String userId) { userVO.setPassword(CryptoUtils.decrypt(userVO.getPassword())); return userVO; } - + /** * 로그인 정보 조회 - * @param userId 사용자ID - * @param password 패스워드 + * @param userLoginInfo UserLoginInfo * @return 로그인VO */ - public LoginVO selectLoginInfo(String userId, String password) { + //public LoginVO selectLoginInfo(String userId, String password) { + public UserVO selectLoginInfo(UserLoginInfo userLoginInfo) + throws NotFoundUserInfoException, NotMatchPatientPasswordException { // 사용자 정보 조회 - LoginVO loginVO = new LoginVO(); - UserVO userVO = selectUserInfo(userId); - - // 로그인 성공 여부 확인 - if (userVO == null) { - loginVO.setFailMessage("사용자 정보를 확인하세요."); - } else { - // 암호확인 - if (!password.equals(userVO.getPassword())) { - loginVO.setFailMessage("암호를 확인하세요."); - } - } - - loginVO.setUserVO(userVO); - return loginVO; + UserVO userVO = selectUserInfo(userLoginInfo.getLoginId()); + + if (userVO == null) { + throw new NotFoundUserInfoException(messageSource.getMessage("message.notfound.userInfo" + ,null, Locale.getDefault())); + } else if (userVO.getPassword().equals(userLoginInfo.getPassword())) { + throw new NotMatchPatientPasswordException(messageSource.getMessage("message.mismatch.password" + , null, Locale.getDefault())); + } + + return userVO; } /** @@ -141,6 +154,15 @@ public void updateUser(UserVO vo) { userDao.updateUser(vo); } + /** + * 로그인 정보 업데이트 + * @param vo UserVO + */ + @Transactional(rollbackFor = Exception.class) + public void updateUserLoginInfo(UserVO vo) { + userDao.updateUserLoginInfo(vo); + } + /** * 사용자 삭제 * @param userId 사용자Id diff --git a/src/main/java/kr/co/hconnect/vo/UserVO.java b/src/main/java/kr/co/hconnect/vo/UserVO.java index 1f486af..181078e 100644 --- a/src/main/java/kr/co/hconnect/vo/UserVO.java +++ b/src/main/java/kr/co/hconnect/vo/UserVO.java @@ -1,7 +1,6 @@ package kr.co.hconnect.vo; import kr.co.hconnect.common.BaseDefaultVO; - import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -38,7 +37,13 @@ public class UserVO extends BaseDefaultVO { * 리마크 */ private String remark; - - //센터명 + /** + * 센터명 + */ private String centerNm; + /** + * 로그인 유지 여부 + */ + private String rememberYn; + } diff --git a/src/main/resources/config/context-common.xml b/src/main/resources/config/context-common.xml index 49caa44..0a3ae00 100644 --- a/src/main/resources/config/context-common.xml +++ b/src/main/resources/config/context-common.xml @@ -114,6 +114,11 @@ POST + + + POST + + diff --git a/src/main/resources/message/message-common.properties b/src/main/resources/message/message-common.properties index 6251779..d56eabd 100644 --- a/src/main/resources/message/message-common.properties +++ b/src/main/resources/message/message-common.properties @@ -76,6 +76,7 @@ message.notfound.loginId=해당 로그인 아이디가 존재하지 않습니다 message.notfound.notice=신규 알림이 없습니다 message.notfound.searchResultList=측정결과가 존재하지 않습니다 message.notfound.searchQuarantine=격리상태 내역이 존재하지 않습니다 +message.notfound.userInfo=사용자 정보가 존재하지 않습니다 # message - Duplicate message.duplicate.admissionInfo=중복된 격리/입소내역이 존재합니다 message.duplicate.patientInfo=동일한 환자정보가 존재합니다 diff --git a/src/main/resources/sqlmapper/user.xml b/src/main/resources/sqlmapper/user.xml index cf8e625..032a705 100644 --- a/src/main/resources/sqlmapper/user.xml +++ b/src/main/resources/sqlmapper/user.xml @@ -10,6 +10,7 @@ , USER_NM AS USER_NM -- 사용자명 , CENTER_ID AS CENTER_ID -- 센터ID , REMARK AS REMARK -- 리마크 + , REMEMBER_YN AS REMEMBER_YN -- 로그인 유지 여부 , REG_ID AS REG_ID -- 등록자ID , REG_DT AS REG_DT -- 등록일시 , UPD_ID AS UPD_ID -- 수정자ID @@ -72,6 +73,15 @@ ]]> + + + + +