

pnpm install next-recaptcha-v3
# pnpm-lock.yml
dependencies:
next-recpatch-v3:
specifier: 13.2.4
version: 13.2.4(@babel/core@7.21.8)(react-dom@18.2.0)(react@18.2.0)
해당 depency가 있으면 설치가 완료된 것이다.
// _app.jsx
import { ReCaptchaProvider } from 'next-recaptcha-v3';
export default function App({Component, pageProps}) {
return (
<ReCaptchaProvider reCaptchaKey={사이트키}
scriptProps={{
async: true,
defer: false,
appendTo: "head",
nonce: undefined
}}
>
<Component {...pageProps} />
</ReCaptchaProvider>
)
}
const {executeRecaptcha} = useRecaptcha() // reCaptcha API 서버로 보낸다. 라는 훅을 선언
const token = executeRecaptcha('login') // reCaptcha API 서버에 토큰 발급을 요청. 안에 있는 값은 실행한 액션 값으로 임의로 주면 된다.
이를 로그인에 사용하면 이렇게 된다.
// 모듈
import { useCallback } from "react";
import { useForm } from "react-hook-form";
import axios from "axios";
import { useReCaptcha } from "next-recaptcha-v3";
const Login = () => {
const {handleSubmit, register, reset} = useForm()
const {executeRecaptcha} = useRecaptcha()
const onSubmit = useCallback(async (data) => {
const token = executeRecaptcha('login') // reCaptcha API 서버에 토큰을 요청. 토큰을 받는다.
const sendData = {
token: token,
id: data.id,
password: data.password
} // 토큰을 사용자 정보와 함께 보낸다
axios.post(`{process.env.NEXT_PUBLIC_URL}/login`, sendData, {
withCredentials: true
}).then((res) => {
console.log(res)
}).catch((error) => {
console.log(error)
})
}, [executeRecaptcha])
// 발급받은 토큰과 사용자 정보를 백엔드로 보낸다.
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<input type="text"
placeholder="id"
{...register("userId")} />
</div>
<div>
<input type="password"
placeholder="pw"
{...register("password")} />
</div>
<button type="submit" >login</button>
</form>
)
}
export default Login
recaptcha:
secret_key: 시크릿 키
verify_url: "https://www.google.com/recaptcha/api/siteverify"
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class CaptchaService {
@Value("${recaptcha.verify_url}")
private String url;
@Value("${recaptcha.secret_key}")
private String key;
private static final double HALF = 0.5;
public boolean verifyToken(String token) { // token은 프론트에서 보낸 요청받은 token이다.
try {
HttpHeaders httpHeaders= new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("secret", key);
map.add("response", token);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class); // 해당 url로 token과 secret key를 전송. 유효성 검증.
JsonObject jsonObject = JsonParser.parseString(response.getBody()).getAsJsonObject();
return String.valueOf(jsonObject.get("success")).equals("true") && Double.parseDouble(String.valueOf(jsonObject.get("score"))) >= HALF;
// success이거나 점수가 0.5 이상인 경우 통과
} catch (Exception e) {
return false;
}
}
}
response의 body에는 이렇게 결과가 떨어진다.
{
"success": true,
"challenge_ts": "2023-05-25T06:46:19Z",
"hostname": "localhost",
"score": 0.9,
"action": "login"
}
score는 0~1 사이의 값으로 1에 가까우면 인간이라는 뜻이다.
Can you push your all codes into github?
Thanks