diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/BijiHoudaunApplication.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/BijiHoudaunApplication.java index 92de2f5..9943c2d 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/BijiHoudaunApplication.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/BijiHoudaunApplication.java @@ -2,8 +2,10 @@ package com.test.bijihoudaun; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class BijiHoudaunApplication { public static void main(String[] args) { diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/SystemController.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/SystemController.java new file mode 100644 index 0000000..db433e4 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/SystemController.java @@ -0,0 +1,50 @@ +package com.test.bijihoudaun.controller; + +import com.test.bijihoudaun.common.response.R; +import com.test.bijihoudaun.service.RegistrationCodeService; +import com.test.bijihoudaun.service.SystemSettingService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; + +@RestController +@RequestMapping("/system") +@Tag(name = "系统管理") +public class SystemController { + + @Autowired + private SystemSettingService systemSettingService; + + @Autowired + private RegistrationCodeService registrationCodeService; + + @GetMapping("/registration/status") + @Operation(summary = "获取注册功能状态") + public R isRegistrationEnabled() { + return R.success(systemSettingService.isRegistrationEnabled()); + } + + @PostMapping("/registration/toggle") + @PreAuthorize("isAuthenticated()") + @Operation(summary = "切换注册功能状态") + public R toggleRegistration(@RequestBody Boolean enabled) { + systemSettingService.setRegistrationEnabled(enabled); + return R.success(); + } + + @PostMapping("/registration/generate-code") + @PreAuthorize("isAuthenticated()") + @Operation(summary = "生成注册码") + public R generateRegistrationCode() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String currentUserName = authentication.getName(); + String code = registrationCodeService.generateCode(currentUserName); + return R.success(code); + } +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/UserController.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/UserController.java index 75ea2ad..59226af 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/UserController.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/UserController.java @@ -2,6 +2,8 @@ package com.test.bijihoudaun.controller; import com.test.bijihoudaun.common.response.R; import com.test.bijihoudaun.entity.User; +import com.test.bijihoudaun.service.RegistrationCodeService; +import com.test.bijihoudaun.service.SystemSettingService; import com.test.bijihoudaun.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -24,14 +26,27 @@ public class UserController { @Autowired private UserService userService; + @Autowired + private SystemSettingService systemSettingService; + + @Autowired + private RegistrationCodeService registrationCodeService; + @Operation(summary = "用户注册") @Parameters({ @Parameter(name = "username", description = "用户名",required = true), @Parameter(name = "password", description = "密码",required = true), - @Parameter(name = "email", description = "邮箱",required = true) + @Parameter(name = "email", description = "邮箱",required = true), + @Parameter(name = "registrationCode", description = "注册码", required = true) }) @PostMapping("/register") - public R register(String username, String password, String email){ + public R register(String username, String password, String email, String registrationCode){ + if (!systemSettingService.isRegistrationEnabled()) { + return R.fail("注册功能已关闭"); + } + if (!registrationCodeService.validateCode(registrationCode)) { + return R.fail("无效或已过期的注册码"); + } return R.success(userService.register(username,password,email)); } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java new file mode 100644 index 0000000..2fd66c1 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/RegistrationCode.java @@ -0,0 +1,34 @@ +package com.test.bijihoudaun.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@TableName("registration_codes") +@Schema(description = "注册码实体") +public class RegistrationCode implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + @Schema(description = "主键ID", name = "id") + private Long id; + + @Schema(description = "注册码", name = "code") + private String code; + + @Schema(description = "过期时间", name = "expiryTime") + private LocalDateTime expiryTime; + + @Schema(description = "创建者", name = "createdBy") + private String createdBy; + + @Schema(description = "创建时间", name = "createdAt") + private LocalDateTime createdAt; +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java new file mode 100644 index 0000000..700dda3 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/entity/SystemSetting.java @@ -0,0 +1,26 @@ +package com.test.bijihoudaun.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +@Data +@TableName("system_settings") +@Schema(description = "系统设置实体") +public class SystemSetting implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId + @Schema(description = "设置键", name = "settingKey") + private String settingKey; + + @Schema(description = "设置值", name = "settingValue") + private String settingValue; + + @Schema(description = "设置描述", name = "description") + private String description; +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/RegistrationCodeMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/RegistrationCodeMapper.java new file mode 100644 index 0000000..ad06cf3 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/RegistrationCodeMapper.java @@ -0,0 +1,9 @@ +package com.test.bijihoudaun.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.test.bijihoudaun.entity.RegistrationCode; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface RegistrationCodeMapper extends BaseMapper { +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/SystemSettingMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/SystemSettingMapper.java new file mode 100644 index 0000000..8965e28 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/SystemSettingMapper.java @@ -0,0 +1,9 @@ +package com.test.bijihoudaun.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.test.bijihoudaun.entity.SystemSetting; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface SystemSettingMapper extends BaseMapper { +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/RegistrationCodeService.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/RegistrationCodeService.java new file mode 100644 index 0000000..980d2ff --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/RegistrationCodeService.java @@ -0,0 +1,10 @@ +package com.test.bijihoudaun.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.test.bijihoudaun.entity.RegistrationCode; + +public interface RegistrationCodeService extends IService { + String generateCode(String creator); + boolean validateCode(String code); + void deleteExpiredCodes(); +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/SystemSettingService.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/SystemSettingService.java new file mode 100644 index 0000000..3466e09 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/SystemSettingService.java @@ -0,0 +1,9 @@ +package com.test.bijihoudaun.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.test.bijihoudaun.entity.SystemSetting; + +public interface SystemSettingService extends IService { + boolean isRegistrationEnabled(); + void setRegistrationEnabled(boolean enabled); +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/RegistrationCodeServiceImpl.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/RegistrationCodeServiceImpl.java new file mode 100644 index 0000000..a81b142 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/RegistrationCodeServiceImpl.java @@ -0,0 +1,55 @@ +package com.test.bijihoudaun.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.test.bijihoudaun.entity.RegistrationCode; +import com.test.bijihoudaun.mapper.RegistrationCodeMapper; +import com.test.bijihoudaun.service.RegistrationCodeService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Service +public class RegistrationCodeServiceImpl extends ServiceImpl implements RegistrationCodeService { + + @Override + public String generateCode(String creator) { + RegistrationCode registrationCode = new RegistrationCode(); + String code = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16); + registrationCode.setCode(code); + registrationCode.setCreatedBy(creator); + registrationCode.setExpiryTime(LocalDateTime.now().plusDays(1)); + save(registrationCode); + return code; + } + + @Override + @Transactional + public boolean validateCode(String code) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", code); + RegistrationCode registrationCode = getOne(queryWrapper); + + if (registrationCode == null) { + return false; + } + + if (registrationCode.getExpiryTime().isBefore(LocalDateTime.now())) { + remove(queryWrapper); // 注册码过期,删除 + return false; + } + + // 验证成功后立即删除,确保一次性使用 + remove(queryWrapper); + return true; + } + + @Override + @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行 + public void deleteExpiredCodes() { + remove(new QueryWrapper().lt("expiry_time", LocalDateTime.now())); + } +} \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/SystemSettingServiceImpl.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/SystemSettingServiceImpl.java new file mode 100644 index 0000000..a63275d --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/impl/SystemSettingServiceImpl.java @@ -0,0 +1,28 @@ +package com.test.bijihoudaun.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.test.bijihoudaun.entity.SystemSetting; +import com.test.bijihoudaun.mapper.SystemSettingMapper; +import com.test.bijihoudaun.service.SystemSettingService; +import org.springframework.stereotype.Service; + +@Service +public class SystemSettingServiceImpl extends ServiceImpl implements SystemSettingService { + + private static final String REGISTRATION_ENABLED_KEY = "registration.enabled"; + + @Override + public boolean isRegistrationEnabled() { + SystemSetting setting = getById(REGISTRATION_ENABLED_KEY); + // 默认开启注册 + return setting == null || Boolean.parseBoolean(setting.getSettingValue()); + } + + @Override + public void setRegistrationEnabled(boolean enabled) { + SystemSetting setting = new SystemSetting(); + setting.setSettingKey(REGISTRATION_ENABLED_KEY); + setting.setSettingValue(String.valueOf(enabled)); + saveOrUpdate(setting); + } +} \ No newline at end of file diff --git a/biji-qianduan/src/api/CommonApi.js b/biji-qianduan/src/api/CommonApi.js index 038d207..ef362b5 100644 --- a/biji-qianduan/src/api/CommonApi.js +++ b/biji-qianduan/src/api/CommonApi.js @@ -66,6 +66,7 @@ export const register = (data) => { const formData = new FormData() formData.append('username', data.username) formData.append('password', data.password) + formData.append('registrationCode', data.registrationCode) return axiosApi.post('/api/user/register', formData, { headers: { 'Content-Type': 'multipart/form-data' @@ -132,3 +133,20 @@ export const cleanTrash = () => axiosApi.delete('/api/trash/clean'); // 验证Token export const validateToken = () => axiosApi.post('/api/user/validate-token'); + +// System APIs +export const getRegistrationStatus = () => { + return axiosApi.get('/system/registration/status'); +}; + +export const toggleRegistration = (enabled) => { + return axiosApi.post('/system/registration/toggle', enabled, { + headers: { + 'Content-Type': 'application/json' + } + }); +}; + +export const generateRegistrationCode = () => { + return axiosApi.post('/system/registration/generate-code'); +}; diff --git a/biji-qianduan/src/components/HomePage.vue b/biji-qianduan/src/components/HomePage.vue index 8b2fe39..5f731be 100644 --- a/biji-qianduan/src/components/HomePage.vue +++ b/biji-qianduan/src/components/HomePage.vue @@ -88,6 +88,7 @@