자동로그인 방지기능 만들기
- SPRING
- 2018. 3. 28. 16:35
오랜만에 스프링 카테고리에 글을 쓰는것 같다.
이번 포스팅에서는 자동로그인 방지 기능이 되겠다.
먼저 어떤 사이트에서 로그인을 할때 위 이미지 와 같은
자동 로그인 방지 기능들을 본적이 있을것이다.
굉장히 유용 하니 한번 알아보자.
먼저 위의 기능을 캡차 라고 부른다.
CAPTCHA란?
HIP 기술의 일종으로 어떠한 사용자가
실제 사람인지 컴퓨터 프로그램인지를 구별하기 위해
사용되는 방법이다. 사람은 구별할 수 있지만 컴퓨터는
구별하기 힘들게 의도적으로 비틀거나
덧칠한 그림을 주고 그 그림에 쓰여 있는 내용을
물어보는 방법이 자주 사용된다. 이것은 기존의 텍스트와 이미지를
일그러뜨린 형태로 변형한 후 인식 대상이 변형된
이미지로부터 기존 이미지를 도출해 낼 수 있는지를
확인하는 방식의 테스트이다.
컴퓨터 프로그래밍이 변형시킨 이미지는 사람이 쉽게
인식 할 수 있지만 컴퓨터 프로그램은 변형된 이미지를 인식하지
못하므로 테스트를 통과하지 못한다면
테스트 대상이 사람이 아님을 판정 할 수 있다.
흔히 웹사이트 회원가입을 할 때 뜨는 자동가입 방지
프로그램 같은 곳에 쓰인다.
CAPTCHA는 기기가 사람을 대상으로 하는 테스트이므로
사람에 가까운 기기를 대상으로 하는
테스트인 튜링 테스트 에서 용어를 따와
리튜링테스트 라고 부르기도 한다.
먼저 캡차를 사용하기 위해선 jar 파일을 하나 받아서
lib폴더에 넣어줘야한다.
난 simplecaptcha-1.2.1.jar 를 사용하였다.
(https://sourceforge.net/projects/simplecaptcha/)
위 사이트에서 Download 에서 다운받을수도 있다.
다음 자르파일을 프로젝트의 lib 폴더에 넣어주자
(참고로 나는 테스트를 위해 전자정부프레임워크를 사용했다
이클립스나 STS에서도 사용할수 있을것이다.)
다음 프로젝트 우클릭후 Properties 에 들어가자.
다음 왼쪽에서 Java Build Path 선택후 Libraries에서 Add External JARs...
를 눌러 워크스페이스에서 lib 경로에 들어가 위에 넣었던 자르파일을
선택해준다.
다음 본격적으로 소스코드 작성을 해보자.
먼저 login.jsp 화면이다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <div class="form-group"> <label for="captcha" style="display:block;">자동 로그인 방지</label> <div class="captcha"> <div class="form-group"> <img id="captchaImg" title="캡차 이미지" src="captchaImg.do" alt="캡차 이미지" /> <div id="captchaAudio" style="display:none;"></div> </div> <div class="form-group"> <a onclick="javascript:refreshBtn()" class="refreshBtn"> <input type="button" value="새로고침" /> </a> <a onclick="javascript:audio()" class="refreshBtn"> <input type="button" value="음성듣기" /> </a> </div> <div class="form-group"> <input type="text" name="answer" id="answer" class="form-control" /> </div> </div> </div> | cs |
먼저 로그인 화면에 자동로그인 방지기능을 넣기위한 소스코드를
작성한다. 캡차 이미지가 뜨고 이미지 안의
숫자들을 새로고침 과 음성듣기 할수있는 버튼을 만들어 줬다.
다음 login.jsp 스크립트단에 아래를 추가하자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | function audio(){ var rand = Math.random(); var url = 'captchaAudio.do'; $.ajax({ url: url, type: 'POST', dataType: 'text', data: 'rand=' + rand, async: false, success: function(resp) { var uAgent = navigator.userAgent; var soundUrl = 'captchaAudio.do?rand=' + rand; if(uAgent.indexOf('Trident') > -1 || uAgent.indexOf('MSIE') > -1) { winPlayer(soundUrl); } else if (!!document.createElement('audio').canPlayType) { try{ new Audio(soundUrl).play(); } catch(e) { winPlayer(soundUrl); } }else { window.open(soundUrl, '', 'width=1, height=1'); } } }); } function refreshBtn(type){ var rand = Math.random(); var url = "captchaImg.do?rand=" + rand; $('#captchaImg').attr("src", url); } function winPlayer(objUrl){ $('#captchaAudio').html('<vgsound src="' + objUrl + '">'); } | cs |
새로고침 버튼을 누르면 이미지 안의 숫자가 바뀌고
음성듣기를 누르면 음성으로 숫자를 알려준다.
다음 컨트롤러를 보자 일단 captchaImg와 captchaAudio를 매핑시켜주자.
1 2 3 4 5 6 7 8 | @RequestMapping(value = "captchaImg.do") public void cpatchaImg(HttpServletRequest request, HttpServletResponse response) throws Exception{ new CaptchaUtil().captchaImg(request, response); } @RequestMapping(value = "captchaAudio.do") public void cpatchaAudio(HttpServletRequest request, HttpServletResponse response) throws Exception{ new CaptchaUtil().captchaAudio(request, response); } | cs |
login.jsp 스크립트단에서 캡차 컨트롤러를 호출하면
이 컨트롤러에서 CaptchaUtil 안의 captchaImg와 captchaAudio메소드를
호출하게 된다.
그럼이제 CaptchaUtil을 만들어주자.
먼저 cmmn 폴더에 CaptchaUtil.java 이름의 파일을 만들어준다.
다음 아래 처럼 만들어준다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | public class CaptchaUtil{ public CaptchaUtil() { } public void captchaImg(HttpServletRequest request, HttpServletResponse response){ Captcha captcha = new Captcha.Builder(200, 60) .addText(new NumbersAnswerProducer(6)) .addNoise().addNoise().addNoise() .addBackground(new GradiatedBackgroundProducer()) .addBorder() .build(); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Max-Age", 0); response.setContentType("image/png"); CaptchaServletUtil.writeImage(response, captcha.getImage());; request.getSession().setAttribute("captcha", captcha.getAnswer()); } public void captchaAudio(HttpServletRequest request, HttpServletResponse response){ String getAnswer = (String) request.getSession().getAttribute("captcha"); AudioCaptcha ac = new AudioCaptcha.Builder() .addAnswer(new SetTextProducer(getAnswer)) .addVoice() .addNoise() .build(); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Max-Age", 0); CaptchaServletUtil.writeAudio(response, ac.getChallenge());; request.getSession().setAttribute("captcha", ac.getAnswer()); } } | cs |
6line에서는 캡차 이미지의 크기를 설정한다.
다음 7line에서는 이미지 안의 숫자를 6개로 설정한다.
8line에서는 이미지안의 숫자를 선을 그어 가려주기위함이다.
9line은 배경색 10line은 테두리 이다.
19line에서 writeImage에 캡차 이미지를 그려준다.
20line에서는 세션에 값을 저장해준다.
26line에서는 문자열을 전달한다.
36line에서 오디오를 그려준다.
다음 이미지와 똑같이 세션에 값을 저장한다.
다음
SetTextProducer.java를 만들어준다. 난 똑같이 cmmn에 넣었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class SetTextProducer implements TextProducer { private final String _getAnswer; public SetTextProducer(String getAnswer){ _getAnswer = getAnswer; } @Override public String getText() { return _getAnswer; } } | cs |
TextProducer인터페이스를 상속받는 클래스를 만들어줘야하는데
오디오 캡차가 전달받은 문자열을 사용할 수 있게 해주는 클래스다.
이제 로그인 처리를 할때 자동 로그인 방지를 위해
입력받은 문자열 값과, 캡차 세션값을 비교해서 사용하면 된다.
라고 하고 포스팅을 끝내고 싶지만 분명 못쓰는 분들이
있을것 같기 때문에, 끝까지 포스팅을 해야겠죠..?
(필자도 캡차 기능 글을 보고 테스트할때 글쓴분이 저렇게 글을 끝냈다는...)
먼저 로그인 기능을 구현할때 아이디, 비밀번호를 치고 캡차 이미지속
숫자를 따라 쓰고 로그인을 할것이다.
먼저 로그인폼에서 값을 입력하면 컨트롤러로 갈것이기 때문에
컨트롤러에서 작업을 해줘야 할것이다.
먼저 위에서 소스를 보면 캡차속 이미지의 값을 세션에 저장했을 것이다.
그리고 로그인 폼에서 나는 answer라는 이름으로 캡차속 이미지 숫자를 입력할수있는
인풋태그를 사용했다. 그럼 먼저 세션에 저장되어있는 캡차속 이미지와
로그인폼에서 입력한 캡차이미지 속의 숫자를 컨트롤러로 가져와야한다.
나는 아래의 방법으로 두 개의 값을 가져왔다.
1 2 | String getAnswer = (String) request.getSession().getAttribute("captcha"); String answer = request.getParameter("answer"); | cs |
그리고 조건을 걸어주면 된다. 보통 로그인 기능에서
아이디와 비밀번호가 db에 저장되있는 값과 비교를 해서
로그인을 할텐데, 여기서 조건을 하나 더 걸어주면 될것같다.
(나는 기존에 쓰던 로그인기능에 조건을 걸어줬다)
1 2 3 4 5 | if(getAnswer.equals(answer)){ System.out.println("로그인 성공."); }else{ System.out.println("로그인 실패."); } | cs |
난 getAnswer.equals(answer)를 사용했다.
내 로그인 기능이 다른사람들과 다르니 정확한 답을 쓸수는 없지만
대충 위의 소스를 보면 어디서 어떤식으로 조건을 줘야할지는
알수 있을 것이다...
'SPRING' 카테고리의 다른 글
ajax에서 JSON.parse(), JSON.stringify() 마스터하기 (0) | 2018.07.03 |
---|---|
JsonUtil에 JsonToMap 사용하기 (0) | 2018.07.03 |
@RequestBody, @ResponseBody (0) | 2018.03.02 |
JSON.stringify(); JSON.parse();사용하기 (0) | 2018.03.02 |
SPRING - Mybatis 사용하기(3) (0) | 2018.02.13 |