Develop
[JAVA]구글 OTP 구현 + QR코드 본문
serviceImpl
@Override
public boolean otpLogin(SOMap rmap) throws Exception {
SOOMap var = Util.getSOOVmap(rmap);
SOOMap dbparams = new SOOMap();
String userNo = p.getStr("userNo");
dbparams.put("userNo", userNo);
String otpKey = userDao.selectOtpKey(dbparams);
if (Util.isNotEmpty(userNo) && Util.isEmpty(otpKey)) {
var.put("otpKeyYn", "N");
// 개인키 생성
String privatekey = GoogleOTPUtil.getSecretKey();
// 주소
String URL = GoogleOTPUtil.getGoogleOTPAuthURL(privatekey, "유저아이디", "사이트이름");
// QRCode 생성
String img = GoogleOTPUtil.getQRImage(URL, 200, 200);
// 개인키 db저장
dbparams.put("otpKey", privatekey);
userDao.updateOtpKey(dbparams);
var.put("img", img);
var.put("URL", URL);
var.put("privatekey", privatekey);
}else{
var.put("otpKeyYn", "Y");
}
return true;
}
@Override
public boolean otpLoginAct(SOMap p ,SOMap rmap) throws Exception {
SOMap var = Util.getSOVmap(rmap);
SOMap dbparams = new SOMap();
String userNo = p.getStr("userNo"); // 유저번호
String otpNum = p.getStr("otpNum"); // 유저가 입력한 값
if(Util.isEmpty(userNo)){
rmap.put(Const.D_SCRIPT, Util.jsmsgLink("잘못된 접근입니다.", "/manager/main/index.do", "T"));
return false;
}
if(Util.isEmpty(otpNum)){
rmap.put(Const.D_SCRIPT, Util.jsmsgLink("인증번호를 입력해주세요.", "/manager/main/otp_login.do", "T"));
return false;
}
// 개인키 값 가져오기
dbparams.put("userNo", userNo);
String otpKey = userDao.selectOtpKey(dbparams); // 개인키
String code = GoogleOTPUtil.getTOTPCode(otpKey);
if(!code.equals(otpNum)){
return false;
}
return true;
}
구글 검색시 나오는 코드를 참조하였고
QR코드만 생성이 안되길래 코드를 조금 바꿨다
* import 확인필수(Base64 import를 잘못해서 한참 해맸음 ㅠ)
package apps.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import de.taimos.totp.TOTP;
/**
* 구글 OTP 관련 클래스
*/
public class GoogleOTPUtil {
// 최초 개인키 생성
public static String getSecretKey(){
SecureRandom random = new SecureRandom();
byte[] bytes = new byte[20];
random.nextBytes(bytes);
Base32 base32 = new Base32();
return base32.encodeToString(bytes);
}
// OTP검증 요청 시 확인
public static String getTOTPCode(String secretKey){
Base32 base32 = new Base32();
byte[] bytes = base32.decode(secretKey);
String hexKey = String.valueOf(Hex.encodeHex(bytes));
return TOTP.getOTP(hexKey);
}
// 개인키, 계정명(유저 아이디), 발급자(회사명or소속)을 받아서 구글OTP 인증용 링크를 생성하는 메소드
public static String getGoogleOTPAuthURL(String secretKey, String account, String issuer){
try{
return "otpauth://totp/"
+ URLEncoder.encode(issuer + ":" + account, "UTF-8").replace("+", "%20")
+ "?secret=" + URLEncoder.encode(secretKey, "UTF-8").replace("+", "%20")
+ "&issuer=" + URLEncoder.encode(issuer, "UTF-8").replace("+", "%20");
}catch(UnsupportedEncodingException e){
throw new IllegalStateException(e);
}
}
// url, 파일 생성할 경로를 받아서 QR코드 이미지 생성
public static String getQRImage(String otpUrl, int height, int width) throws WriterException, IOException {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = qrCodeWriter.encode(otpUrl, BarcodeFormat.QR_CODE, width, height, hints);
ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
byte[] qrCodeImage = pngOutputStream.toByteArray();
qrCodeImage = Base64.encodeBase64(qrCodeImage);
String img = new String(qrCodeImage, "UTF-8");
return img;
}
}
뷰페이지에서 출력이 고민된다면
https://sseb32310.tistory.com/133
참고한 글
Two-Factor Authentication with Java and Google Authenticator
I am more than sure that each of you have at least one account with enabled Two-Factor Authentication (2FA). But if you are still…
medium.com
https://creampuffy.tistory.com/89
Google OTP 인증 Java로 구현하기
OTP는 One Time Password의 약자이다. 일회용이라는 측면에서 보안에 더욱 강력하다고 알려져 있다. 자바에서 구현하기 위해 여러 링크를 둘러봤는데 아래 링크가 가장 크게 도움이 됐다. medium.com/@ihor
creampuffy.tistory.com
'웹 개발 > Java' 카테고리의 다른 글
[JAVA] redirect 리다이렉트 + 데이터 전달 (0) | 2024.09.30 |
---|---|
[JAVA] byte[] 데이터를 String으로 변환후 뷰(JSP)에 출력하기 (0) | 2024.09.04 |
[JAVA] 파일 다운로드 / 파일 이름 및 확장자 오류 해결 (0) | 2024.07.30 |
QR Code 생성 및 출력하기 (0) | 2024.05.16 |
[JAVA] Bcrypt를 이용하여 비밀번호 암호화하기 (0) | 2024.02.26 |