공부/그룹 스터디

[4회차 03] 인증 유효성 검사

junani0v0 2024. 4. 24. 20:37

_45dc6c54-2497-4020-8fc4-9081d7621038

인증 유효 검사

인증 유효한지 검사 = 유효시간보다 작아야
유효 시간 비교 => 숫자 timestamp

image-24

자바에서 시간비교는 timestamp로 하며 sql에서는 DateTime으로 합니다
그러므로 expire_dtm 쿼리의 Data Type을 DateTime으로 변경해 줍니다

MemberAuthDao

public int addAuthInfo(MemberAuthDto dto) {

    String sql ="INSERT INTO forum.member_auth "
            + "(member_seq, auth_num, auth_uri, reg_dtm, expire_dtm, auth_yn) "
            + "VALUES(" + dto.getMemberSeq()
            + ", '', '" + dto.getAuthUri()
            + "', DATE_FORMAT(NOW()  ,'%Y%m%d%H%i%s'), "
            + "DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 30 MINUTE),'%Y%m%d%H%i%s'), 'N'); ";

    return update(sql);
}

기존 MemberAuthDao에서 유효시간(expire_dtm)을 30분 더하였지만 이제는 자바에서 비교를 할것이기에 자바에서 사용할 수 있게 고치겠습니다.

MemberAuthDto

expire_dtm의 타입을 숫자로 바꿔주는데 int와 Long중 Long으로 바꿔주세요(아니면 길어서 못담습니다)

public class MemberAuthDto {
    private int authSeq;
    private int memberSeq;
    private String authNum;
    private String authUri;
    private String regDtm;
    private Long expireDtm;
    private String authYn;

    public int getAuthSeq() {
        return authSeq;
    }
    public void setAuthSeq(int authSeq) {
        this.authSeq = authSeq;
    }
    public int getMemberSeq() {
        return memberSeq;
    }
    public void setMemberSeq(int memberSeq) {
        this.memberSeq = memberSeq;
    }
    public String getAuthNum() {
        return authNum;
    }
    public void setAuthNum(String authNum) {
        this.authNum = authNum;
    }
    public String getAuthUri() {
        return authUri;
    }
    public void setAuthUri(String authUri) {
        this.authUri = authUri;
    }
    public String getRegDtm() {
        return regDtm;
    }
    public void setRegDtm(String regDtm) {
        this.regDtm = regDtm;
    }
    public long getExpireDtm() {
        return expireDtm;
    }
    public void setExpireDtm(Long expireDtm) {
        this.expireDtm = expireDtm;
    }
    public String getAuthYn() {
        return authYn;
    }
    public void setAuthYn(String authYn) {
        this.authYn = authYn;
    }
}

MemberAuthRowMapper

public class MemberAuthRowMapper implements ResultSetExtractor<MemberAuthDto>{

    @Override
    public MemberAuthDto extractData(ResultSet rs) throws SQLException {
    MemberAuthDto dto = null;
    while(rs.next()) { 
        dto = new MemberAuthDto();
        dto.setAuthSeq(rs.getInt("auth_seq"));
        dto.setMemberSeq(rs.getInt("member_seq"));
        dto.setAuthNum(rs.getString("auth_num"));
        dto.setAuthUri(rs.getString("auth_uri"));
        dto.setRegDtm(rs.getString("reg_dtm"));
        dto.setExpireDtm(rs.getLong("expire_dtm"));
        dto.setAuthYn(rs.getString("auth_yn"));
    }
    return dto;
    }
}

MemberAuthRowMapper에서 setExpireDtm의 타입도 Long으로 변경해줍니다

JoinService

authDto.setExpireDtm(Calendar.getInstance().getTimeInMillis());

Calendar에 get인스턴스를 한 뒤
getTimeInMillis를 해줍니다
여기서 30분을 더해줘야하기에 코드를 한번 더 바꾸면

Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 30);
authDto.setExpireDtm(cal.getTimeInMillis());

을 넣어 아래처럼 완성합니다

    public int join(HashMap<String, String> params) {
        String passwd = params.get("passwd");

        String encPasswd = BCrypt.withDefaults().hashToString(12, passwd.toCharArray());
        System.out.println("encPasswd >>>>>>>>> " + encPasswd);

        BCrypt.Result result = BCrypt.verifyer().verify(passwd.toCharArray(), encPasswd);
        System.out.println("result.verified >>>>>>> " + result.verified);

        params.put("passwd", encPasswd);

        int cnt = memberDao.join(params);
        int memberSeq = memberDao.getMemberSeq(params.get("memberId"));
        if (cnt == 1) {
            // 인증 메일 구조 만들기
            MemberAuthDto authDto = new MemberAuthDto();
            authDto.setMemberSeq(memberSeq);
            authDto.setAuthUri(UUID.randomUUID().toString().replaceAll("-", ""));

            Calendar cal = Calendar.getInstance();
            cal.add(Calendar.MINUTE, 30);
            authDto.setExpireDtm(cal.getTimeInMillis());

            memberAuthDao.addAuthInfo(authDto);

            // 인증 메일 발송
            EmailDto email = new EmailDto();
            email.setFrom("portfolio98@naver.com");
            email.setReceiver(params.get("email"));
            email.setSubject("인증하세요");
            // host + contextRoot + URI
            String html = "<a href='http://localhost:8080/04/emailAuth.do?uri="+ authDto.getAuthUri() +"'>인증하기</>";
            email.setText(html);

            emailUtil.sendMail(email, true);
        }

//        return memberDao.join(params);
        return cnt;
    }

이걸 이제 Dto에 담았으니 쿼리를 고치려 가야합니다

MemberAuthDao

public int addAuthInfo(MemberAuthDto dto) {

    String sql ="INSERT INTO forum.member_auth "
            + "(member_seq, auth_num, auth_uri, reg_dtm, expire_dtm, auth_yn) "
            + "VALUES(" + dto.getMemberSeq()
            + ", '', '" + dto.getAuthUri()
            + "', DATE_FORMAT(NOW()  ,'%Y%m%d%H%i%s'), "
            + "" + dto.getExpireDtm()
            + ", 'N'); ";

    return update(sql);
}

expire_dtm에 dto.getExpireDtm()을 넣어줍니다

JoinService

public boolean emailAuth(String uri) {
    MemberAuthDto dto = memberAuthDao.getMemberAuthDto(uri);
    System.out.println(dto.getAuthYn());
    System.out.println(dto.getRegDtm());
    System.out.println(dto.getExpireDtm());
    }

    return false;
}

현재 ExpireDtm은 Long으로 숫자를 넣었지만 sql에 집어넣을땐 Calendar로 집어 넣었기에 대소 비교를 위해 현재시간을 같은 타입으로 변경합니다

Long now = = Calendar.getInstance().getTimeInMillis();

여기서 현재값(now)이 ExpireDtm보다 작아야하기에 아래처럼 작성할 수 있습니다

boolean result = now < dto.getExpireDtm();
    if (result) {
        // member_auth -> auth_yn : Y
    }

이 코드를 추가해 emailAuth메서드를 완성시키면

public boolean emailAuth(String uri) {
    MemberAuthDto dto = memberAuthDao.getMemberAuthDto(uri);
    System.out.println(dto.getAuthYn());
    System.out.println(dto.getRegDtm());
    System.out.println(dto.getExpireDtm());

    // 인증이 유효한지 검사
    long now = Calendar.getInstance().getTimeInMillis();

    boolean result = now < dto.getExpireDtm();
    if (result) {
        // member_auth -> auth_yn : Y
    }
    return result;
}

이제 이 result에 따라 메시지를 전달해줄 수 있습니다

LoginController

@RequestMapping("/emailAuth.do")
public ModelAndView emailAuth(@RequestParam("uri") String uri) {
    ModelAndView mv = new ModelAndView();
    mv.setViewName("login");
    boolean result = joinService.emailAuth(uri);
    mv.addObject("result", result);
    String msg = result ? "인증 성공":"인증 실패";
    mv.addObject("msg",msg);

    return mv;
}

LoginController에 JoinService의 emailAuth의 return 값 result로 "인증 성공","인증 실패" 메시지를 결정할 수 있게 코드를 추가해줍니다

이제 서버를 시작해 회원가입을 해보면 DB에 값이 잘려서 나옵니다

  • 데이터 잘리는 이유 : DB에 설정한 타입인 DateTime보다 값이 길어 발생

이걸 해결하기위해 Expire_dtm의 Data Type을 Long으로 바꿔야하는데 sql에는 Long이 없으므로 BIGINT로 변경해줍니다

MemberAuthDao

public MemberAuthDto getMemberAuthDto(String uri) {
    String sql ="SELECT auth_seq, member_seq, auth_num, auth_uri, reg_dtm, expire_dtm, auth_yn "
            + "FROM forum.member_auth "
            + "WHERE auth_uri ='"+uri+"' AND auth_yn='N'";
    return query(sql, new MemberAuthRowMapper());
}

MemberAuthDao에서 SELECT의 WHERE절에 auth_yn이 N(인증 안된)
것만 검색하게 조건을 추가해 줍니다