-
Notifications
You must be signed in to change notification settings - Fork 0
로그인
Gaeun Kim edited this page Feb 26, 2023
·
3 revisions
👆🏻 로그인 화면
- 사용자가 입력한 ID를 기반으로 DB에서 회원 정보 조회
- 조회되는 정보가 있다면 사용자가 입력한 비밀번호와 DB에 암호화되어 저장된 비밀번호의 일치 여부 확인
- 비밀번호가 일치하다면 session에 저장
3-1. 관리자일 경우 관리자 페이지로 이동
3-2. 일반회원일 경우 메인 페이지로 이동
MemberController
@PostMapping("/login") // 사용자가 입력한 ID와 PW를 담는 Map
public ModelAndView login(CommitMap commitMap,
HttpServletRequest request,
HttpSession session) throws Exception {
ModelAndView mv = new ModelAndView();
// 회원정보 조회
Map<String, Object> memberInfo = memberService.getMemberDetail(commitMap.getMap(), request);
// 아이디를 잘못 입력했을경우
if (memberInfo == null) {
mv.addObject("msg", "아이디 또는 비밀번호를 잘못 입력했습니다.");
mv.addObject("path", "/member/login");
mv.setViewName("/alert/alert");
return mv;
}
// 간편 로그인 회원이라면
if (memberInfo.get("OAUTH") != null) {
mv.addObject("msg", "간편 로그인을 이용해주세요.");
mv.addObject("path", "/member/login");
mv.setViewName("/alert/alert");
return mv;
}
// 사용자가 입력한 비밀번호
String rowPassword = commitMap.get("MEM_PW").toString();
// DB에 암호화되어 저장된 비밀번호
String encodePassword = memberInfo.get("MEM_PW").toString();
// BCryptPasswordEncoder로 일치 여부 확인
if (encoder.matches(rowPassword, encodePassword)) {
// 관리자
if (memberInfo.get("ADMIN").equals("Y")) {
session.setAttribute("MEM_ID", memberInfo.get("MEM_ID"));
session.setAttribute("MEM_NAME", memberInfo.get("MEM_NAME"));
session.setAttribute("admin", memberInfo.get("ADMIN"));
mv.setViewName("redirect:/admin/main");
// 일반 회원
} else {
session.setAttribute("MEM_ID", memberInfo.get("MEM_ID"));
session.setAttribute("MEM_NAME", memberInfo.get("MEM_NAME"));
mv.setViewName("redirect:/main");
}
// 비밀번호 불일치
} else {
mv.addObject("msg", "아이디 또는 비밀번호를 잘못 입력했습니다.");
mv.addObject("path", "/member/login");
mv.setViewName("/alert/alert");
}
return mv;
}
MemberServiceImpl
@Override
public Map<String, Object> getMemberDetail(Map<String, Object> map, HttpServletRequest request) throws Exception {
/* 다른 Controller(ex. MyController)에서 getMemberDetail메소드를 호출할 때는 map에 MEM_ID가 담겨있지 않음. 대신 request를 통해 session에서 MEM_ID 값을 얻어옴.
(로그인 요청시에만 map에 MEM_ID가 담겨있음) */
if (map.get("MEM_ID") == null) {
map = sessionHelper.make(map, request);
}
Map<String, Object> memberInfo = memberDAO.selectMemberDetail(map);
if (memberInfo != null) {
if (memberInfo.get("ZIPCODE") != null && !"".equals(memberInfo.get("ZIPCODE").toString())) {
// 주소 분리 작업(MyPage 정보 수정에서 사용) - ADDRESS컬럼에 '도로명주소 + | + 상세주소'로 들어가 있음.
String totalAddress = memberInfo.get("ADDRESS").toString();
int index = totalAddress.indexOf("|");
String loadAddress = totalAddress.substring(0, index);
String addressDetail = totalAddress.substring(index + 1);
memberInfo.put("ROAD_ADDRESS", loadAddress);
memberInfo.put("ADDRESS_DETAIL", addressDetail);
}
}
return memberInfo;
}
Member_SQL.xml
SELECT MEM_ID,
MEM_PW,
MEM_NAME,
PHONE,
ZIPCODE,
ADDRESS,
EMAIL,
EMAIL_AGREE,
ADMIN,
OAUTH
FROM MEMBER
WHERE MEM_ID = LOWER(#{MEM_ID})
AND DEL = 'N'
사용자가 입력한 이름과 전화번호로 DB에서 일치하는 회원이 있는지 조회 후 사용자의 아이디를 보여준다.
MemberController
@PostMapping("/findID")
public ModelAndView findID(CommitMap commitMap, HttpServletRequest request) throws Exception {
// 조회되는 회원이 있다면 1 없다면 0
int member = memberService.findMemberByInfo(commitMap.getMap(), request);
ModelAndView mv = new ModelAndView();
if (member == 0) {
mv.addObject("msg", "해당 정보를 가진 회원이 없습니다.");
mv.addObject("path", "/member/findID");
mv.setViewName("/alert/alert");
} else {
String findID = memberService.findID(commitMap.getMap());
mv.addObject("MEM_ID", findID);
mv.setViewName("/member/successFindID");
}
return mv;
}
MemberServiceImpl
@Override
public int findMemberByInfo(Map<String, Object> map, HttpServletRequest request) {
String requestURI = request.getRequestURI();
// map에 findID라는 값을 넣는 이유는 코드 1-2를 참고해주세요.
if("/member/findID".equals(requestURI)){
map.put("findID", "findID");
}
return memberDAO.selectMemberByInfo(map);
}
코드 1-1
Member_SQL.xml
SELECT COUNT(*)
FROM MEMBER
WHERE
<if test="findID != NULL">
MEM_NAME = #{MEM_NAME} AND PHONE = #{PHONE}
</if>
<if test="findID == NULL">
MEM_ID = LOWER(#{MEM_ID}) AND EMAIL = LOWER(#{EMAIL})
</if>
코드 1-2
-
파라미터로 들어오는 map에 FindID라는 값이 있다면 - 아이디 찾기(이름과 전화번호로 회원 조회)
-
파라미터로 들어오는 map에 FindID라는 값이 없다면 - 비밀번호 찾기(아이디와 이메일로 회원 조회)
ID 찾기 결과
사용자가 입력한 아이디와 이메일로 DB에서 일치하는 회원이 있는지 조회 후 회원가입시 입력한 이메일로 임시 비밀번호를 발급한다.
MemberController
@PostMapping("/findPW")
public ModelAndView findPW(CommitMap commitMap, HttpServletRequest request) throws Exception {
// 조회되는 회원이 있다면 1 없다면 0
int member = memberService.findMemberByInfo(commitMap.getMap(), request);
ModelAndView mv = new ModelAndView();
if (member == 0) {
mv.addObject("msg", "해당 정보를 가진 회원이 없습니다.");
mv.addObject("path", "/member/findPW");
mv.setViewName("/alert/alert");
} else {
//메일 전송
memberService.sendEmail(commitMap.getMap());
mv.addObject("msg", "임시 비밀번호가 이메일로 전송되었습니다.");
mv.setViewName("/alert/windowClose");
}
return mv;
}
MemberServiceImpl
@Override
public int findMemberByInfo(Map<String, Object> map, HttpServletRequest request) {
String requestURI = request.getRequestURI();
// map에 findID라는 값을 넣는 이유는 ID 찾기 파트의 코드 1-2를 참고해주세요.
if("/member/findID".equals(requestURI)){
map.put("findID", "findID");
}
return memberDAO.selectMemberByInfo(map);
}
회원정보 조회
@Override
public void sendEmail(Map<String, Object> map) throws Exception {
// UUID
String tempPW = CommitUtils.getRandomString().substring(0, 10);
// 임시 비밀번호 암호화
String encodePassword = encoder.encode(tempPW);
map.put("TEMP_PW", encodePassword);
// 암호화된 임시 비밀번호로 회원의 기존 비밀번호 변경
memberDAO.updateTempPW(map);
String lineSeparator = System.lineSeparator() + System.lineSeparator();
String email = map.get("EMAIL").toString();
String commitEmail = "commitpcShop@gmail.com";
String title = "[Commit] 🔑 임시비밀번호 보내드립니다.";
String content = "안녕하세요 Commit입니다." + lineSeparator + "발급된 임시비밀번호를 보내드립니다." + lineSeparator + tempPW;
// 메일 전송
mailService.sendEmail(email, commitEmail, title, content);
}
임시 비밀번호 메일 전송
📩 MailService
public void sendEmail(String toAddress, String fromAddress, String subject, String msgBody) {
SimpleMailMessage smm = new SimpleMailMessage();
//수신자 설정
smm.setTo(toAddress);
//발신자 설정
smm.setFrom(fromAddress);
//메일 제목 설정
smm.setSubject(subject);
//메일 내용 설정
smm.setText(msgBody);
mailSender.send(smm);
}
실제 메일 전송 코드
Member_SQL.xml
SELECT COUNT(*)
FROM MEMBER
WHERE
<if test="findID != NULL">
MEM_NAME = #{MEM_NAME} AND PHONE = #{PHONE}
</if>
<if test="findID == NULL">
MEM_ID = LOWER(#{MEM_ID}) AND EMAIL = LOWER(#{EMAIL})
</if>
회원정보 조회
UPDATE
MEMBER
SET MEM_PW = #{TEMP_PW}
WHERE MEM_ID = LOWER(#{MEM_ID})
임시 비밀번호로 회원의 기존 비밀번호 변경
임시 비밀번호 메일 전송
실제 받은 메일
- 카카오 로그인 API를 연동하여 사용자에 대한 인증, 인가 처리
- 전달받은 인가코드로 액세스 토큰 요청
- 액세스 토큰을 통해 얻은 사용자의 정보를 조합하여 사용자의 아이디 생성
- 생성된 아이디로 기존 회원인지 신규 회원인지 확인
4-1. 기존 회원일 경우 로그인 처리
4-2 신규 회원일 경우 회원가입 페이지로 이동
KakaoLoginController
@GetMapping("/oauth/login")
public String oAuthLogin(String code, Model model, HttpSession session, HttpServletRequest request) throws Exception {
// 인가코드로 액세스 토큰 발급받기
String accessToken = kaKaoLoginService.getAccessToken(code);
// 액세스 토큰으로 userInfo 얻기
KakaoUserInfo userInfo = kaKaoLoginService.getUserInfo(accessToken);
// 가입된 회원인지 확인
int result = kaKaoLoginService.joinCheck(userInfo);
// 가입된 회원이 아님(신규회원)
if (result == 0) {
model.addAttribute("userInfo", userInfo);
return "member/oauthJoinForm";
// 이미 가입된 회원
} else {
Map<String, Object> memberID = kaKaoLoginService.makeUserId(userInfo);
// 회원정보를 꺼내옴
Map<String, Object> memberInfo = memberService.getMemberDetail(memberID, request);
if (memberInfo != null) {
// 로그인 처리
kaKaoLoginService.kakaoLogin(memberInfo, session);
}
return "redirect:/";
}
}
@PostMapping("/oauth/member/join")
public String join(CommitMap commitMap, HttpSession session) throws Exception {
// 회원가입
kaKaoLoginService.join(commitMap.getMap());
// 회원가입 후 로그인 처리
kaKaoLoginService.kakaoLogin(commitMap.getMap(), session);
return "redirect:/";
}
신규 회원일 경우 회원가입
AppConfig
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public HttpHeaders header() {
return new HttpHeaders();
}
@Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
Bean 등록
KakaoLoginService
private final RestTemplate restTemplate;
private final HttpHeaders header;
@Value("${kakao.clientId}")
private String clientId;
@Value("${kakao.redirectURI}")
private String redirectURI;
public KakaoLoginService(RestTemplate restTemplate, HttpHeaders header){
this.restTemplate = restTemplate;
this.header = header;
}
객체 주입 및 properties파일 값 주입
public String getAccessToken(String code) {
// 토큰 발급을 위한 요청 주소
String requestURI = "https://kauth.kakao.com/oauth/token";
// 요청 header 설정
header.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8");
// 요청 body
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "authorization_code");
body.add("client_id", clientId);
body.add("redirect_uri", redirectURI);
body.add("code", code);
// 요청 주소에 보낼 entity
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, header);
AccessTokenInfo tokenInfo = restTemplate.exchange(requestURI, HttpMethod.POST, request, AccessTokenInfo.class).getBody();
return tokenInfo.getAccess_token();
}
액세스 토큰 발급
public KakaoUserInfo getUserInfo(String accessToken) {
String requestURI = "https://kapi.kakao.com/v2/user/me";
header.add("Authorization","Bearer "+accessToken);
HttpEntity<MultiValueMap<String,String>> request = new HttpEntity<>(header);
KakaoUserInfo userInfo = restTemplate.exchange(requestURI, HttpMethod.GET, request, KakaoUserInfo.class).getBody();
// 각 요청마다 같은 header 객체를 공유하기 때문에 clear 해줘야 함.
header.clear();
return userInfo;
}
액세스 토큰으로 사용자 정보 가져오기
public Map<String,Object> makeUserId(KakaoUserInfo userInfo){
Map<String, Object> map = new HashMap<>();
String memId = userInfo.getId() +"_"+ userInfo.getProperties().getNickname() +"_"+ "oauth";
map.put("MEM_ID", memId);
return map;
}
사용자의 정보를 조합하여 사용자의 아이디 생성
public int joinCheck(KakaoUserInfo userInfo) throws Exception {
Map<String, Object> map = makeUserId(userInfo);
// 이미 가입이 되어있다면 1 신규 회원이라면 0
return memberService.confirmId(map);
}
가입된 회원인지 확인
public void join(Map<String, Object> map) throws Exception {
// 아이디 생성(id, nickname 활용 - makeUserId메소드와 생성 규칙 동일)
String id = map.get("ID").toString();
String mem_name = map.get("MEM_NAME").toString();
String mem_id = id +"_"+ mem_name +"_oauth";
map.put("MEM_ID", mem_id);
// oauth 필드(enum 사용)
map.put("OAUTH", Oauth.KAKAO);
// 회원가입
memberService.joinMember(map);
}
회원가입
public void kakaoLogin(Map<String, Object> map, HttpSession session) {
session.setAttribute("MEM_ID",map.get("MEM_ID"));
session.setAttribute("MEM_NAME", map.get("MEM_NAME"));
}
로그인 처리
Member_SQL.xml
SELECT COUNT(MEM_ID)
FROM MEMBER
WHERE MEM_ID = LOWER(#{MEM_ID})