블로그 이미지
App 개발에 대한 내용을 다룰 예정입니다. AppleSherbet

카테고리

분류 전체보기 (39)
한국프로야구 어플 (18)
세미나 (2)
Java Development (13)
Android App소개 (3)
기타 (2)
당근마켓 (1)
Total299,563
Today15
Yesterday32
Setting up a captcha

  이제 우리가 만들 블로그 엔진에 스팸성 Comment 를 달 수 없도록 "Captcha" 를 설정하자. 지식 사전을 참고로 해보면 Captcha란 컴퓨터 사용자가 사람인지를 판단하기 위해 사용되는 일종의 테스트로 스팸 소프트웨어의 자동 계정 등록을 막기 위해 계정 등록할 때 거치는 테스트라고 한다. 일반적으로 특정 싸이트에 가입할때 자주 보는 테스트로 누구든 한번은 해보았을 것이다.

Generating the captcha image

  이제 Play를 이용해 Chapcha 이미지를 생성해보자. 간단히 말하면 우리는 새로운 액션 메소드를 사용할 것이며 이 메소드는 html 을 랜더링 하지 않고 바이너리 스트림을 renderBinary(binarydata) 메소드를 이용해 렌더링 하게 된다. Play 가 full-stack 웹 프레임워크이기 때문에 captcha 기능과 같이 웹어플리케이션에 필수적으로 필요한 요소들은 프레임워크 안에 내장 되어 쉽게 구현가능하도록 지원해준다. 
  play.libs.Images 유틸리티에 아주 간단하게 captcha이미지를 만들어낼 수 있는 Image.Captcha 클래스가 있으며 이 객체를 http 응답으로 쉽게 보낼 수 있다. 예전 처럼 간단한 구현으로 부터 시작해보자.
 
Application controller 에 captcha 액션을 아래와 같이 추가하자.

import play.libs.*.
...
public static void captcha() {
    Images.Captcha captcha = Images.captcha();
    renderBinary(captcha);
}


  코드에서 보면 Play 에서 제공하는 captcha 객체를 생성해서 바로 renderBinary 의 인자로 넘기고 있다. 내부적으로 Images.Captcha 클래스가 java.io.InputStream 인터페이스를 implement 하고 있기 때문에 가능하다.
이제 captcha를 위한 새 route를 추가해보자.
/yabe/conf/routes

GET     /captcha                                Application.captcha

  자 이제 captcha 액션이 잘 추가 됐는지를 테스트 하기 위해 브라우져에서
http://localhost:9000/capcha 를 쳐보자


브라우져를 refresh 할때마다 새로운 이미지가 랜덤으로 생성 될 것이다.

How do we manage the state?

  지금까지는 play에서 제공하는 유틸리티 메소드 덕분에 아주 쉽다. 하지만 지금부터가 중요하다. 입력한 captcha 코드가 실제 유효한지를 판단할려면 해당 이미지의 실제 string 값을 가지고 있다가 그 정보와 유저가 입력한 코드 정보가 일치하는지를 판단해야 한다.
  어떻게 하면 될까? 간단한 방법으론 user session 에다가 해당 스트링 정보를 저장했다가 form 입력시 validation을 체크하는 방법이 있다. 하지만 이 경우 두가지 문제가 발생한다.

  첫째, Play에섯 session은 쿠키에 저장된다. session에 저장되는 데이터는 사이닝되지만 암호화가 되지는 않는다. 그것은 결국 누구나 session 쿠키에 저장된 captcha 정보를 빼낼 수 있다는 뜻이 된다.
  둘째, Play는 stateless 한 웹프레임웤이다. 그래서 순수하게(purely) stateless한 상태를 유지해야 하는 것이 좋다.

위 두가지 문제를 해결하기 위해 캐쉬와 unique ID를 사용하자. captcha 코드에 대한 정보는 임시로 생성됐다 사라지므로 캐쉬를 사용해 서버단에 저장 할 수 있다. 예를들어 10분정도 저장후 자동으로 삭제되는 캐쉬를 이용한다면 더 좋은 보안을 제공할 수 있을것이다. (서버단에 저장하므로 기본적으로 큰 문제는 없다)
  uniqueID는 캐쉬에 저장시 key값으로 사용하기 위해 만들어진다. 즉, key는 uniqueID, value는 유저로 부터 입력된 captcha 코드가 되는 것이다. uniqueID는 view의 hidden field에 감춰져 액션 메소드로 전달된다. captcha 액션을 아래 처럼 수정하자.

import play.cache.*.
...
public static void captcha(String id) {
    Images.Captcha captcha = Images.captcha();
    String code = captcha.getText("#E4EAFD");
    Cache.set(id, code, "10mn");
    renderBinary(captcha);
}


  captcha.getText("#E4EAFD") 메소드를 이용하면 이미지에 보이는 실제 코드값을 구할 수 있다. getText에 색깔을 지정해주는 것은 렌더링 될 captcha 코드 이미지의 색깔은 set해주는 것이다. (왜 이렇게 되있는지는 잘 모르겠다;;) Cache.set 메소드는 uniqueID와 실제 captcha 코드 텍스트 그리고 캐쉬에 저장할 유효 시간을 설정해준다.

Adding the captcha image to the comment form

  이제 comment form 에 이미지를 보여주기 전에 uniqueID 를 생성하는 코드를 추가하자. 그리고 나서 이 uniqueID를 이용하여 view의 form에서 captcha 액션을 호출 해 줄 것이다. Application.show 액션을 수정하자.

public static void show(Long id) {
    Post post = Post.findById(id);
    String randomID = Codec.UUID();
    render(post, randomID);
}


  소스를 보면 Codec.UUID() 메소드를 이용하여 유일한 아이디값을 생성한다음 랜더링시에 인자로 전달하고 있다. 이제 show.html 을 수정하자.
/yabe/app/views/Application/show.html




  소스에서 보면 img 태그를 이용해 captcha 이미지를 뿌려주고 randomID는 hidden field(실제 웹브라우져 상에서 숨겨지는 필드)를 통해 postComment 액션으로 전달된다. (validation을 위한 전달)
  여기까지 구현 했다면 Post 상세 페이지를 가보자 captcha 이미지가 아래처럼 보일 것이다.


Validating the captcha

  이제 넘어온 randomID와 code정보(유저의 입력)를 이용해 validation을 하는 일만 남았다. 즉, 두 값이 같은지를 비교하는 것이다. hidden field로 전달 했기 때문에 postComment 액션에서 사용이 가능하다. postComment 액션을 아래처럼 수정하자.
public static void postComment(
        Long postId, 
        @Required(message="Author is required") String author, 
        @Required(message="A message is required") String content, 
        @Required(message="Please type the code") String code, 
        String randomID) 
{
    Post post = Post.findById(postId);
    validation.equals(
        code, Cache.get(randomID)
    ).message("Invalid code. Please type it again");
    if(validation.hasErrors()) {
        render("Application/show.html", post, randomID);
    }
    post.addComment(author, content);
    flash.success("Thanks for posting %s", author);
    Cache.delete(randomID);
    show(postId);
}

  추가된 인자를 전달 받기위해 postComment 액션의 인자로 String code값과 String randomID값을 추가해 줬다. 또한 randomID값을 키값으로 해서 Cache에서 추출한 코드값과 인자로 넘어온(유저가 입력한) 코드값이 같은지를 체크해 준다. (validation.equals이용) 그리고 마지막에 Cache에서 해당 코드를 삭제 해주면 된다. 몇가지 validation을 추가해준 관계로 에러 메세지의 종류가 늘어났다. 이것을 표시해 주기 위해
show.html 을 조금 수정해주자.

.. 
#{ifErrors}
    

${errors[0]}

#{/ifErrors} …


  단지 배열에 있는 첫번째 에러 코드를 표시해 주는 것으로 충분하다. 이제 완성이다! 잘 동작하는지 확인해보자.


Play framework으로 블로그 개발하기 (5) - Setting up a captcha (끝)
저작자 표시
신고
Posted by AppleSherbet

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

티스토리 툴바