记事本可以做网站吗,温州网站建设专业的公司,无锡市建设局网站联系电话,怎么注册免费个人网站在项目中#xff0c;需要对请求验证#xff0c;防止被爆破#xff0c;这里使用的是谷歌的recaptcha-v3。 1.申请谷歌人机验证的api
申请链接,申请完后需要将两个谷歌颁发的key分别写入前#xff0c;后端的配置环境中#xff0c;后面会使用. 2.前端部分 前端使用的是viteC…在项目中需要对请求验证防止被爆破这里使用的是谷歌的recaptcha-v3。 1.申请谷歌人机验证的api
申请链接,申请完后需要将两个谷歌颁发的key分别写入前后端的配置环境中后面会使用. 2.前端部分 前端使用的是viteCRA框架先放出配置.
vite全局环境配置(vite.config.js)(环境配置记录,验证请看下面).
import { defineConfig, loadEnv } from vite
import ViteTestConfig from ./config/vite.test.config.js
import ViteBaseConfig from ./config/vite.base.config.js// 策略模式做一个动态的配置
const envResolver {build: () {console.log(生产环境)return ({ ...ViteTestConfig, ...ViteBaseConfig })},serve: () {console.log(开发环境)// 另一种写法// return Object.assign({}, ViteBaseConfig, ViteDevConfig)return ({ ...ViteTestConfig, ...ViteBaseConfig })}}// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) {const env loadEnv(mode, process.cwd(), )console.log(env : , env)// 根据不同的环境使用不同的配置文件,注意这个地方的写法非常的奇特return envResolver[command]()}
)
这里使用动态配置vite的环境,vite的config文件当前使用的是本地开发环境使用的是vite.test.config.js其他环境按这样引用就好了环境配置比如hostprot,dir等等都在自己需要的环境config中配置就行了.
同时还需要配置环境变量环境变量使用.env文件这里我创建了个env文件夹然后将环境变量都放进去了需要在vite的环境配置中告诉其环境变量文件位置.
import react from vitejs/plugin-react
import { defineConfig } from vite
export default defineConfig({plugins: [react()],envDir: src/env,
})
同时也分各种不同的环境变量配置格式为:.env.(环境名称) 例如:..env.development
而.env则是默认的环境变量也可以理解为全局变量不管你加不加载都会读取其中的变量.
而vite中的变量命名必须以 VITE_ 开头否则不会读取 例子: VITE_TEST_BASE_URLhttp://127.0.0.1:8080/api 在react中读取变量(react数据共享)
react讲究一个纯函数所以变量声明只能在其组件中使用,这就有一个问题,当我们使用主题或者存储用户token的时候就不能在所有组件中共享如果一个个传递下去非常麻烦所以需要使用到react提供的useContext.
1.创建一个context载体组件
// AppContext.js
import React from reactconst AppContext React.createContext()export default AppContext
2.在父组件中使用
function App() {
// 主题模式const [styleMode, setStyleMode] React.useState(light)//改变页面主题const changeMode () {const newMode styleMode dark ? light : darksetStyleMode(newMode)localStorage.setItem(theme, newMode)}//主题const customTheme createTheme({palette: {mode: styleMode,},})ThemeProvider theme{customTheme}AppContext.Providervalue{{ mode: styleMode, changeMode }}{ElementRouter}/AppContext.Provider/ThemeProvider
}
使用该方式可以将变量在被包裹的组件中使用同时也可以传递函数对父组件中的数据进行修改。 3.子组件调用 直接使用useContext(载体组件名)即可获得变量 //获取全局变量 const { mode, changeMode } useContext(AppContext) //获取环境变量 const variable import.meta.env.定义的环境变量名 在前端引入recaptcha v3
这里使用封装好的组件引入npm安装 npm install react-google-recaptcha-v3 v2的话需要自己去找一下引入方式此方法只适合v3. 引入后在需要引入谷歌验证的父组件上对子组件进行包裹,这里我直接放在APP组件上,直接全部使用了.
function App{return (ThemeProvider theme{customTheme}GoogleReCaptchaProviderreCaptchaKey{import.meta.env.VITE_GOOGLE_CAPCHAT_KEY}//国内谷歌验证useRecaptchaNet{true}AppContext.Providervalue{{ mode: styleMode, baseUrl: baseUrl, changeMode }}{ElementRouter}/AppContext.Provider/GoogleReCaptchaProvider/ThemeProvider)
}
key就是你申请到的前端key(client)useRecaptchaNet一定要开不开的话会去访问谷歌的verifty局域网内是无法访问的.
使用的话v3使用的是一个无感验证不需要用户去进行图片或者人机验证点击所以直接封装一个验证逻辑后放入代码中就好了(比如提交表单的时候或者点击某些按钮的时候等等)
import { requestSlimpePost } from ./RequestUtilsasync function checkRobot (executeRecaptcha, baseUrl) {//人机验证不可用情况if (!executeRecaptcha) {alert(人机验证不可用,请检查网络!)return false}//获得验证tokenconst capChatToken await executeRecaptcha()//获取token失败if (!capChatToken) {alert(人机验证失败!)return false}//封装成json数据const data {capChatToken: capChatToken,}const jsonData JSON.stringify(data, null, 2)//获取返回数据const res await requestSlimpePost(baseUrl /verify/recapchat, jsonData)if (res.msg ! ok || res.code ! 200) {alert(人机验证失败!)console.log(res)return false}return true
}export { checkRobot }
其中requestSlimpePost是我自己封装的请求工具就使用fetch就不过多介绍了. const { executeRecaptcha } useGoogleReCaptcha()const { baseUrl } React.useContext(AppContext)const handleSubmit async (event) {event.preventDefault()//获取当前登录数据const userInputData new FormData(event.currentTarget)const userName userInputData.get(userName)const passwd userInputData.get(passwd)if (!userName) {alert(用户名不能为空)return}if (!passwd) {alert(密码不能为空)return}const notRobot await checkRobot(executeRecaptcha, baseUrl)if (!notRobot) return}先通过封装的包中获取executeRecaptcha这个对象然后通过调用其中函数向谷歌验证申请验证令牌拿到后再通过后端携带该令牌去进行评测. 3.后端部分
在前端获取验证令牌后需要向后端申请验证后端则向谷歌申请该次人机验证的评分并进行逻辑操作.
/*** author Vermouth* ClassName: ReCapChatManager* Description: 人机校验管理器* Date 2024/4/10 11:05* Version: V1.0*/
Component
public class ReCapChatManager {// 请求地址private static final String SITEVE_RIFY https://www.recaptcha.net/recaptcha/api/siteverify;private static OkHttpClient httpClient new OkHttpClient();Autowiredprivate ReCapIpManager reCapIpManager;// 从配置文件中读取到后端keyValue(${recaptcha.server-key})private String serverKey;/*** 人机校验** param request 请求包装类* return true / false* throws IOException*/public boolean robotCheck(HttpServletRequest request) throws IOException {//请求的IPString remoteAddr RequestUtils.getClientIp(request);String requestJson StringUtils.bufferToString(request.getReader());JsonObject requestObj JsonParser.parseString(requestJson).getAsJsonObject();//异常的请求也驳回if (null requestObj) {this.addFreezeIp(remoteAddr);return false;}//请求体设置RequestBody formBody new FormBody.Builder().add(secret, this.serverKey) //服务端key.add(response, requestObj.get(capChatToken).getAsString()) //客户端提交的token//.add(remoteip, remoteAddr) //客户的ip地址不是必须的参数。.build();//请求头设置Headers reqHeaders new Headers.Builder().add(HttpHeaders.CONTENT_TYPE, application/x-www-form-urlencoded;charsetUTF-8).add(HttpHeaders.CONTENT_LENGTH, String.valueOf(formBody.contentLength())).build();//装入请求中Request reRequest new Request.Builder().url(SITEVE_RIFY).headers(reqHeaders).post(formBody).build();Call call httpClient.newCall(reRequest);String responseData null;try {//发起请求Response googleResponse call.execute();//检查是否获取到响应体if (null googleResponse.body()) throw new IOException();responseData googleResponse.body().string();} catch (IOException e) {throw new SystemException(ExceptionStatus.OKHTTP_CALL_EXCEPTION_);}JsonObject jsonObject JsonParser.parseString(responseData).getAsJsonObject();//TODO 后续有了服务器还需接入Cloudflare// 是否执行成功if (!jsonObject.get(success).getAsBoolean()) {// 在失败的情况下获取到异常状态码JsonArray errorCodes jsonObject.get(error-codes).getAsJsonArray();this.addFreezeIp(remoteAddr);return false;}//获取评分double score jsonObject.get(score).getAsDouble();if (score 0.5) {// 如果低于0.5分服务不接受该请求this.addFreezeIp(remoteAddr);return false;}return true;}/*** 冻结ip操作** param ipAddress 需冻结ip*/public void addFreezeIp(String ipAddress) {reCapIpManager.freezeIp(ipAddress);}}需要注意的是请求地址请求地址同样也必须是国内的谷歌验证api否则访问不到.
一般来说打分都是在0.9我自己测试的都是在0.9,可以根据自己的情况来调整判断人机的分数.