JVM/Java

[Java] SimpleCaptcha를 이용한 이미지 보안문자 생성하기

헹창 2020. 1. 23.
반응형

[Java] SimpleCaptcha를 이용한 이미지 보안문자 생성하기

 

 

보안문자코드를 사용해야하는데, SimpleCaptcha를 주로 많이 사용하길래 한 번 써봤다.

 

- 스펙 : 전자정부프레임워크 3.8, 자바1.8

 

1. SimpleCaptcha-1.2.1.jar 파일 다운로드

- 먼저 SimpleCaptcha 홈페이지에 들어가서 Java 버전에 맞는 버전을 다운받자.

 

참고로 SimpleCaptcha라이브러리를 이용한 CAPTCHA 샘플 프로그램은 JDK 1.6 기반이 가장 최신이라 SimpleCaptcha for Java 6을 다운받았다.

 

 

 

2. 다운로드받은 jar파일을 프로젝트에 추가해준다.

 

 

 

방법1. Spring MVC 프로젝트 구조의 WEB-INF의 lib에 위에서 다운받은 jar 파일을 추가해주었다.

 

방법2. 경로를 모르겠거나 어디에 추가해야할지 모른다면, 프로젝트 우클릭 후 [Properties] - [Java Build Path] 에서 Libraries탭에서 Add External JARs 를 하여 다운받은 jar파일을 추가 한 뒤 적용하면 된다.

 

 

 

자. 여기까지 세팅은 끝났다.

 

 

3-1. CaptCha Image 와 Audio 생성해주는 'CaptCha' 클래스 소스 코드

 

import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import nl.captcha.Captcha;
import nl.captcha.audio.AudioCaptcha;
import nl.captcha.backgrounds.GradiatedBackgroundProducer;
import nl.captcha.servlet.CaptchaServletUtil;
import nl.captcha.text.producer.NumbersAnswerProducer;
import nl.captcha.text.renderer.DefaultWordRenderer;

public class CaptchaUtil {
	private static int width = 150;	/*보안문자 이미지 가로크기*/
	private static int height = 50; /*보안문자 이미지 세로크기*/
	
	/*CaptCha Image 생성*/
	public void getImgCaptCha(HttpServletRequest req, HttpServletResponse res) {
		/*폰트 및 컬러 설정*/
		List<Font> fontList = new ArrayList<Font>();
		fontList.add(new Font("", Font.HANGING_BASELINE, 40));
		fontList.add(new Font("Courier", Font.ITALIC, 40));
		fontList.add(new Font("", Font.PLAIN, 40));
		List<Color> colorList = new ArrayList<Color>();
		colorList.add(Color.BLACK);
		
		Captcha captcha = new Captcha.Builder(width,  height)
				// .addText() 또는 아래와 같이 정의 : 6자리 숫자와 폰트 및 컬러 설정
				.addText(new NumbersAnswerProducer(6), new DefaultWordRenderer(colorList, fontList))
				.addNoise().addBorder()
				.addBackground(new GradiatedBackgroundProducer())
				.build();
		
		/*JSP에서 Captcha 객체에 접근할 수 있도록 session에 저장*/
		req.getSession().setAttribute(Captcha.NAME, captcha);
		CaptchaServletUtil.writeImage(res,  captcha.getImage());
	}
	
	/*CaptCha Audio 생성*/
	public void getAudioCaptCha(HttpServletRequest req, HttpServletResponse res, String answer) throws IOException {
		HttpSession session = req.getSession();
		
		Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
		String getAnswer = answer;
		
		if(getAnswer == null || getAnswer.equals("")) getAnswer = captcha.getAnswer();
		
		AudioCaptcha audiocaptcha = new AudioCaptcha.Builder()
				.addAnswer(new SetTextProducer(getAnswer))
				.addNoise()	/*잡음 추가*/
				.build();
		
		CaptchaServletUtil.writeAudio(res,  audiocaptcha.getChallenge());
	}
}

 

 

- 전달받은 문자열을 그대로 AudioCaptCha가 사용할 수 있도록 TextProducer 인터페이스를 상속받는 클래스이다.

 

import nl.captcha.text.producer.TextProducer;

public class SetTextProducer implements TextProducer{
	private final String str;
	
	public SetTextProducer(String getAnswer) {
		this.str = getAnswer;
	}

	@Override
	public String getText() {
		return this.str;
	}
}

 

 

3-2. Controller 소스 코드

 

@Controller
@Slf4j
public class MainController {

	// 페이지 매핑
	@GetMapping("/captcha.do")
	public String Captcha() {
		return "captcha";
	}	

	// captcha 이미지 가져오는 메서드
	@GetMapping("/captchaImg.do")
	@ResponseBody
	public void captchaImg(HttpServletRequest req, HttpServletResponse res) throws Exception{
		new CaptchaUtil().getImgCaptCha(req, res);
	}

	// 전달받은 문자열로 음성 가져오는 메서드
	@GetMapping("/captchaAudio.do")
	@ResponseBody
	public void captchaAudio(HttpServletRequest req, HttpServletResponse res) throws Exception{
		Captcha captcha = (Captcha) req.getSession().getAttribute(Captcha.NAME);
		String getAnswer = captcha.getAnswer();
		new CaptchaUtil().getAudioCaptCha(req, res, getAnswer);
	}

	// 사용자가 입력한 보안문자 체크하는 메서드
	@PostMapping("/chkAnswer.do")
	@ResponseBody
	public String chkAnswer(HttpServletRequest req, HttpServletResponse res) {
		String result = "";
		Captcha captcha = (Captcha) req.getSession().getAttribute(Captcha.NAME);
		String ans = req.getParameter("answer");
		if(ans!=null && !"".equals(ans)) {
			if(captcha.isCorrect(ans)) {
				req.getSession().removeAttribute(Captcha.NAME);
				result = "200";
			}else {
				result = "300";
			}
		}
		return result;
	}
}

 

 

3.3 JSP 소스코드

 

- html

 

<label for="captcha" style="display:block">자동 로그인 방지</label>
<div style="overflow:hidden">
	<div style="float:left">
		<img title="캡차이미지" src="/captchaImg.do" alt="캡차이미지"/>
		<div id="ccaudio" style="display:none"></div>
	</div>
</div>
<div style="padding:3px">
	<input id="reload" type="button" onclick="javaScript:getImage()" value="새로고침"/>
	<input id="soundOn" type="button" onclick="javaScript:audio()" value="음성듣기"/>
</div>
<div style="padding:3px">	
	<input id="answer" type="text" value="">
	<input id="check" type="button" value="확인"/>
</div>

 

 

- javascript  (jQuery를 사용하지 않는 순수 자바스크립트 구현 코드이다.)

 

window.onload = function(){
	getImage();	// 이미지 가져오기
	
	document.querySelector('#check').addEventListener('click', function(){
		var params = {answer : document.querySelector('#answer').getAttribute('value')};
		AF.ajax('${ctx}/chkAnswer.do', params, function(returnData){
			if(returnData == 200){
				alert('입력값이 일치합니다.');
				// 성공 코드
			}else{
				alert('입력값이 일치하지 않습니다.');
				getImage();
				document.querySelector('#answer').setAttribute('value', '');
			}
		}, 'json');
	});
}
/*매번 랜덤값을 파라미터로 전달하는 이유 : IE의 경우 매번 다른 임의 값을 전달하지 않으면 '새로고침' 클릭해도 정상 호출되지 않아 이미지가 변경되지 않는 문제가 발생된다*/
function audio(){
	var rand = Math.random();
	var uAgent = navigator.userAgent;
	var soundUrl = '${ctx}/captchaAudio.do?rand='+rand;
	if(uAgent.indexOf('Trident')>-1 || uAgent.indexOf('MISE')>-1){	/*IE 경우 */
		audioPlayer(soundUrl);
	}else if(!!document.createElement('audio').canPlayType){ /*Chrome 경우 */
		try {
			new Audio(soundUrl).play();
		} catch (e) {
			audioPlayer(soundUrl);
		}
	}else{
		window.open(soundUrl,'','width=1,height=1');
	}
}
function getImage(){
	var rand = Math.random();
	var url = '${ctx}/captchaImg.do?rand='+rand;
	document.querySelector('img').setAttribute('src', url);
}
function audioPlayer(objUrl){
	document.querySelector('#ccaudio').innerHTML = '<bgsoun src="' +objUrl +'">';
}

 

* AF.ajax는 ajax를 jQuery없이 구현하기 위해 만든 코드이니 이 부분에서는 사용하던 ajax코드를 사용하면 된다.

 

 

 

4. 구현완료 화면

 

 

 

 

 

 

 

728x90
반응형

댓글

추천 글