diff --git a/server/package.json b/server/package.json index 8e592967..8a6cc097 100644 --- a/server/package.json +++ b/server/package.json @@ -4,11 +4,10 @@ "description": "survey server template", "main": "index.js", "scripts": { - "copy": "mkdir -p ./build/ && cp -rf ./src/* ./build/", "build": "tsc", - "start:stable": "npm run copy && npm run build && SERVER_ENV=stable node ./build/index.js", - "start:preonline": "npm run copy && npm run build && SERVER_ENV=preonline node ./build/index.js", - "start:online": "npm run copy && npm run build && SERVER_ENV=online node ./build/index.js", + "start:stable": "npm run build && SERVER_ENV=stable node ./build/index.js", + "start:preonline": "npm run build && SERVER_ENV=preonline node ./build/index.js", + "start:online": "npm run build && SERVER_ENV=online node ./build/index.js", "start": "npm run start:online", "local": "npx ts-node scripts/run-local.ts", "dev": "npx ts-node-dev ./src/index.ts" @@ -35,7 +34,8 @@ "koa-router": "^12.0.0", "lodash": "^4.17.21", "moment": "^2.29.4", - "mongodb": "^5.7.0" + "mongodb": "^5.7.0", + "svg-captcha": "^1.4.0" }, "engines": { "node": ">=14.21.0", diff --git a/server/src/apps/user/index.ts b/server/src/apps/user/index.ts index 69d9bd1b..746079f0 100644 --- a/server/src/apps/user/index.ts +++ b/server/src/apps/user/index.ts @@ -2,17 +2,29 @@ import { SurveyServer } from '../../decorator' import { Request, Response } from 'koa' import * as Joi from 'joi' import { userService } from './service/userService' +import { captchaService } from './service/captchaService' import { getValidateValue } from './utils/index' - +import { CommonError } from '../../types/index' export default class User { @SurveyServer({ type: 'http', method: 'post', routerName: '/register' }) async register({ req, res }: { req: Request, res: Response }) { const userInfo = getValidateValue(Joi.object({ username: Joi.string().required(), password: Joi.string().required(), + captchaId: Joi.string().required(), + captcha: Joi.string().required(), }).validate(req.body, { allowUnknown: true })); - const userRegisterRes = await userService.register(userInfo) + const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }) + if (!isCorrect) { + throw new CommonError('验证码不正确') + } + const userRegisterRes = await userService.register({ + username: userInfo.username, + password: userInfo.password, + }) + // 删除验证码 + captchaService.deleteCaptcha({ id: userInfo.captchaId }) return { code: 200, data: userRegisterRes, @@ -24,8 +36,19 @@ export default class User { const userInfo = getValidateValue(Joi.object({ username: Joi.string().required(), password: Joi.string().required(), + captchaId: Joi.string().required(), + captcha: Joi.string().required(), }).validate(req.body, { allowUnknown: true })); - const data = await userService.login(userInfo) + const isCorrect = await captchaService.checkCaptchaIsCorrect({ captcha: userInfo.captcha, id: userInfo.captchaId }) + if (!isCorrect) { + throw new CommonError('验证码不正确') + } + const data = await userService.login({ + username: userInfo.username, + password: userInfo.password, + }) + // 删除验证码 + captchaService.deleteCaptcha({ id: userInfo.captchaId }) return { code: 200, data, @@ -40,4 +63,21 @@ export default class User { context, // 上下文主要是传递调用方信息使用,比如traceid } } + + @SurveyServer({ type: 'http', method: 'post', routerName: '/captcha' }) + async refreshCaptcha({ req }) { + const captchaData = captchaService.createCaptcha() + const res = await captchaService.addCaptchaData({ text: captchaData.text }) + if (req.body && req.body.captchaId) { + // 删除验证码 + captchaService.deleteCaptcha({ id: req.body.captchaId }) + } + return { + code: 200, + data: { + id: res.insertedId, + img: captchaData.data, + }, + } + } } \ No newline at end of file diff --git a/server/src/apps/user/service/captchaService.ts b/server/src/apps/user/service/captchaService.ts new file mode 100644 index 00000000..d3a4a2de --- /dev/null +++ b/server/src/apps/user/service/captchaService.ts @@ -0,0 +1,40 @@ +import { mongo } from '../db/mongo' +import { create } from 'svg-captcha' +class CaptchaService { + + createCaptcha() { + return create({ + size: 4, // 验证码长度 + ignoreChars: '0o1i', // 忽略字符 + noise: 3, // 干扰线数量 + color: true, // 启用彩色 + background: '#f0f0f0', // 背景色 + }) + } + + async addCaptchaData({ text }) { + const captchaDb = await mongo.getCollection({ collectionName: 'captcha' }); + const addRes = await captchaDb.insertOne({ + text, + }); + return addRes; + } + + async checkCaptchaIsCorrect({ captcha, id }) { + const captchaDb = await mongo.getCollection({ collectionName: 'captcha' }); + const captchaData = await captchaDb.findOne({ + _id: mongo.getObjectIdByStr(id), + }); + return captcha.toLowerCase() === captchaData?.text?.toLowerCase(); + } + + async deleteCaptcha({ id }) { + const captchaDb = await mongo.getCollection({ collectionName: 'captcha' }); + const _id = mongo.getObjectIdByStr(id) + await captchaDb.deleteOne({ + _id + }) + } +} + +export const captchaService = new CaptchaService() \ No newline at end of file diff --git a/server/src/apps/user/utils/index.ts b/server/src/apps/user/utils/index.ts index dcb99a09..98861030 100644 --- a/server/src/apps/user/utils/index.ts +++ b/server/src/apps/user/utils/index.ts @@ -1,15 +1,15 @@ import { SURVEY_STATUS, CommonError } from '../../../types/index' -import * as Joi from 'joi' -export function getStatusObject({status}:{status:SURVEY_STATUS}) { +import * as Joi from 'joi' +export function getStatusObject({ status }: { status: SURVEY_STATUS }) { return { status, id: status, date: Date.now(), }; } -export function getValidateValue(validationResult:Joi.ValidationResult):T { - if(validationResult.error) { - throw new CommonError(validationResult.error.details.map(e=>e.message).join()) +export function getValidateValue(validationResult: Joi.ValidationResult): T { + if (validationResult.error) { + throw new CommonError(validationResult.error.details.map(e => e.message).join()) } return validationResult.value; } \ No newline at end of file diff --git a/web/src/management/api/captcha.js b/web/src/management/api/captcha.js new file mode 100644 index 00000000..55e589b3 --- /dev/null +++ b/web/src/management/api/captcha.js @@ -0,0 +1,5 @@ +import axios from './base'; + +export const refreshCaptcha = ({ captchaId }) => { + return axios.post('/user/captcha', { captchaId }); +}; diff --git a/web/src/management/api/user.js b/web/src/management/api/user.js index e2dfd7c1..6883867d 100644 --- a/web/src/management/api/user.js +++ b/web/src/management/api/user.js @@ -1,15 +1,9 @@ import axios from './base'; -export const register = ({ username, password }) => { - return axios.post('/user/register', { - username, - password, - }); +export const register = (data) => { + return axios.post('/user/register', data); }; -export const login = ({ username, password }) => { - return axios.post('/user/login', { - username, - password, - }); +export const login = (data) => { + return axios.post('/user/login', data); }; diff --git a/web/src/management/pages/login/index.vue b/web/src/management/pages/login/index.vue index 110b012e..06e9af9e 100644 --- a/web/src/management/pages/login/index.vue +++ b/web/src/management/pages/login/index.vue @@ -12,19 +12,33 @@ diff --git a/web/src/render/components/logo.vue b/web/src/render/components/logo.vue index 9a5386b1..c2179064 100644 --- a/web/src/render/components/logo.vue +++ b/web/src/render/components/logo.vue @@ -1,12 +1,12 @@