Skip to content

Commit

Permalink
bump: 发布2.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
uncarbon97 authored Sep 21, 2024
1 parent 68d74ca commit dd6f533
Show file tree
Hide file tree
Showing 72 changed files with 1,252 additions and 1,171 deletions.
7 changes: 7 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# https://hub.docker.com/_/eclipse-temurin/tags?page=1&name=alpine
FROM eclipse-temurin:17.0.7_7-jre-alpine
COPY ./bootstrap/target/*.jar ./app.jar
COPY entrypoint.sh /
RUN chmod +x ./entrypoint.sh && \
ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone
ENTRYPOINT ["./entrypoint.sh"]
8 changes: 4 additions & 4 deletions api/admin-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
<parent>
<groupId>cc.uncarbon.module</groupId>
<artifactId>helio-boot-modular</artifactId>
<version>2.1.0</version>
<version>2.2.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>admin-api</artifactId>
<version>2.1.0</version>
<version>2.2.0</version>

<properties>
<!-- 引入其他服务模块 -->
<!-- 后台管理服务 -->
<sys.version>2.1.0</sys.version>
<sys.version>2.2.0</sys.version>
<!-- 对象存储服务 -->
<oss.version>2.1.0</oss.version>
<oss.version>2.2.0</oss.version>
</properties>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package cc.uncarbon.module.adminapi.aspect.extension;

import cc.uncarbon.module.sys.annotation.SysLog;
import cc.uncarbon.module.sys.extension.impl.DefaultSysLogAspectExtension;
import cc.uncarbon.module.sys.model.request.AdminInsertSysLogDTO;
import cc.uncarbon.module.sys.model.request.SysUserLoginDTO;
import lombok.NoArgsConstructor;
import org.aspectj.lang.JoinPoint;

/**
* SysLog 切面实现类扩展 for 登录后台用户
*/
@NoArgsConstructor
public class SysLogAspectExtensionForSysUserLogin extends DefaultSysLogAspectExtension {

@Override
public void beforeSaving(AdminInsertSysLogDTO insertSysLogDTO, JoinPoint joinPoint, SysLog annotation, Throwable e, Object ret) {
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof SysUserLoginDTO dto) {
insertSysLogDTO.setUsername(dto.getUsername());
}
}
}
}
package cc.uncarbon.module.adminapi.aspect.extension;

import cc.uncarbon.module.sys.annotation.SysLog;
import cc.uncarbon.module.sys.extension.impl.DefaultSysLogAspectExtension;
import cc.uncarbon.module.sys.model.request.AdminInsertSysLogDTO;
import cc.uncarbon.module.sys.model.request.SysUserLoginDTO;
import lombok.NoArgsConstructor;
import org.aspectj.lang.JoinPoint;

/**
* SysLog 切面实现类扩展 for 登录后台用户
*/
@NoArgsConstructor
public class SysLogAspectExtensionForSysUserLogin extends DefaultSysLogAspectExtension {

@Override
public void beforeSaving(AdminInsertSysLogDTO insertSysLogDTO, JoinPoint joinPoint, SysLog annotation, Throwable e, Object ret) {
for (Object arg : joinPoint.getArgs()) {
if (arg instanceof SysUserLoginDTO dto) {
insertSysLogDTO.setUsername(dto.getUsername());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package cc.uncarbon.module.adminapi.constant;


/**
* 后台管理接口常量
*/
public final class AdminApiConstant {
private AdminApiConstant() {
}

/**
* HTTP-API路由前缀
*/
public static final String HTTP_API_URL_PREFIX = "/admin";

}
package cc.uncarbon.module.adminapi.constant;


/**
* 后台管理接口常量
*/
public final class AdminApiConstant {
private AdminApiConstant() {
}

/**
* HTTP-API路由前缀
*/
public static final String HTTP_API_URL_PREFIX = "/admin";

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@
public enum AdminApiErrorEnum implements HelioBaseEnum<Integer> {

CAPTCHA_GENERATE_FAILED(500, "验证码生成失败,请稍后再试"),

CAPTCHA_VALIDATE_FAILED(400, "验证码不正确,请重新输入"),

/**
* 很少遇到;但是如果出现了只会提示默认的「请稍后再试」,不方便排查,还是整个文案比较好
*/
UPLOAD_FILE_NOT_EXIST(400, "欲上传的文件可能已被删除,请重新选择");
// 很少遇到;但是如果出现了只会提示默认的「请稍后再试」,不方便排查,还是整个文案比较好
UPLOAD_FILE_NOT_EXIST(400, "欲上传的文件可能已被删除,请重新选择"),;

private final Integer value;
private final String label;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
package cc.uncarbon.module.adminapi.event;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEvent;

import java.util.Collection;

/**
* 强制登出后台用户事件
*/
@Getter
public final class KickOutSysUsersEvent extends ApplicationEvent {

private final transient EventData data;

public KickOutSysUsersEvent(EventData data) {
super(data);
this.data = data;
}

@Getter
@RequiredArgsConstructor
public static final class EventData {

/**
* 需要被强制登出的后台用户IDs
*/
private final Collection<Long> sysUserIds;

}
}
package cc.uncarbon.module.adminapi.event;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEvent;

import java.util.Collection;

/**
* 强制登出后台用户事件
*/
@Getter
public final class KickOutSysUsersEvent extends ApplicationEvent {

private final transient EventData data;

public KickOutSysUsersEvent(EventData data) {
super(data);
this.data = data;
}

@Getter
@RequiredArgsConstructor
public static final class EventData {

/**
* 需要被强制登出的后台用户IDs
*/
private final Collection<Long> sysUserIds;

}
}
Original file line number Diff line number Diff line change
@@ -1,94 +1,94 @@
package cc.uncarbon.module.adminapi.helper;

import cc.uncarbon.framework.core.exception.BusinessException;
import cc.uncarbon.module.adminapi.enums.AdminApiErrorEnum;
import cc.uncarbon.module.adminapi.model.interior.AdminCaptchaContainer;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.CharSequenceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

/**
* 验证码助手类;可将验证码答案缓存至 Redis
*
* @author Uncarbon
*/
@Component
@RequiredArgsConstructor
public class CaptchaHelper {

private final RedisTemplate<String, String> stringRedisTemplate;

private static final String CACHE_KEY_CAPTCHA_ANSWER = "Authorization:captcha:uuid_%s";

/**
* 验证码答案长度
*/
private static final int CAPTCHA_ANSWER_LENGTH = 4;

/**
* 生成一个验证码
*/
public AdminCaptchaContainer generate() {
// redis预占位;随机10个UUID,应该有个能成的吧……
UUID uuid = UUID.randomUUID();
String captchaCacheKey = null;
Boolean stubFlag = Boolean.FALSE;
for (int count = 0; count < 10; count++) {
captchaCacheKey = String.format(CACHE_KEY_CAPTCHA_ANSWER, uuid.toString(true));
stubFlag = stringRedisTemplate.opsForValue().setIfAbsent(captchaCacheKey, CharSequenceUtil.EMPTY);
if (Boolean.TRUE.equals(stubFlag)) {
break;
}
uuid = UUID.randomUUID();
}
if (!Boolean.TRUE.equals(stubFlag)) {
throw new BusinessException(AdminApiErrorEnum.CAPTCHA_GENERATE_FAILED);
}

// 定义图形验证码的长、宽、验证码字符数、干扰线宽度
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(196, 50, CAPTCHA_ANSWER_LENGTH, 4);

// 将验证码答案保存至 redis, 有效期5分钟
stringRedisTemplate.opsForValue().set(captchaCacheKey, captcha.getCode(), 300, TimeUnit.SECONDS);
LocalDateTime expiredAt = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), 300, ChronoUnit.SECONDS);

return new AdminCaptchaContainer(captcha, uuid.toString(true), expiredAt);
}

/**
* 核验验证码是否输入正确
*
* @param uuid 验证码唯一标识(UUID)
* @param captchaAnswer 验证码答案
* @return 是否正确
*/
public boolean validate(String uuid, String captchaAnswer) {
if (CharSequenceUtil.hasBlank(uuid, captchaAnswer)) {
return false;
}

String cacheKey = String.format(CACHE_KEY_CAPTCHA_ANSWER, uuid);
boolean equals;
try {
if (CharSequenceUtil.length(captchaAnswer) != CAPTCHA_ANSWER_LENGTH) {
// 长度不同
return false;
}

String answerInRedis = stringRedisTemplate.opsForValue().get(cacheKey);
equals = CharSequenceUtil.equalsIgnoreCase(answerInRedis, captchaAnswer);
} finally {
stringRedisTemplate.delete(cacheKey);
}
return equals;
}
}
package cc.uncarbon.module.adminapi.helper;

import cc.uncarbon.framework.core.exception.BusinessException;
import cc.uncarbon.module.adminapi.enums.AdminApiErrorEnum;
import cc.uncarbon.module.adminapi.model.interior.AdminCaptchaContainer;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.CharSequenceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

/**
* 验证码助手类;可将验证码答案缓存至 Redis
*
* @author Uncarbon
*/
@Component
@RequiredArgsConstructor
public class CaptchaHelper {

private final RedisTemplate<String, String> stringRedisTemplate;

private static final String CACHE_KEY_CAPTCHA_ANSWER = "Authorization:captcha:uuid_%s";

/**
* 验证码答案长度
*/
private static final int CAPTCHA_ANSWER_LENGTH = 4;

/**
* 生成一个验证码
*/
public AdminCaptchaContainer generate() {
// redis预占位;随机10个UUID,应该有个能成的吧……
UUID uuid = UUID.randomUUID();
String captchaCacheKey = null;
Boolean stubFlag = Boolean.FALSE;
for (int count = 0; count < 10; count++) {
captchaCacheKey = String.format(CACHE_KEY_CAPTCHA_ANSWER, uuid.toString(true));
stubFlag = stringRedisTemplate.opsForValue().setIfAbsent(captchaCacheKey, CharSequenceUtil.EMPTY);
if (Boolean.TRUE.equals(stubFlag)) {
break;
}
uuid = UUID.randomUUID();
}
if (!Boolean.TRUE.equals(stubFlag)) {
throw new BusinessException(AdminApiErrorEnum.CAPTCHA_GENERATE_FAILED);
}

// 定义图形验证码的长、宽、验证码字符数、干扰线宽度
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(196, 50, CAPTCHA_ANSWER_LENGTH, 4);

// 将验证码答案保存至 redis, 有效期5分钟
stringRedisTemplate.opsForValue().set(captchaCacheKey, captcha.getCode(), 300, TimeUnit.SECONDS);
LocalDateTime expiredAt = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), 300, ChronoUnit.SECONDS);

return new AdminCaptchaContainer(captcha, uuid.toString(true), expiredAt);
}

/**
* 核验验证码是否输入正确
*
* @param uuid 验证码唯一标识(UUID)
* @param captchaAnswer 验证码答案
* @return 是否正确
*/
public boolean validate(String uuid, String captchaAnswer) {
if (CharSequenceUtil.hasBlank(uuid, captchaAnswer)) {
return false;
}

String cacheKey = String.format(CACHE_KEY_CAPTCHA_ANSWER, uuid);
boolean equals;
try {
if (CharSequenceUtil.length(captchaAnswer) != CAPTCHA_ANSWER_LENGTH) {
// 长度不同
return false;
}

String answerInRedis = stringRedisTemplate.opsForValue().get(cacheKey);
equals = CharSequenceUtil.equalsIgnoreCase(answerInRedis, captchaAnswer);
} finally {
stringRedisTemplate.delete(cacheKey);
}
return equals;
}
}
Loading

0 comments on commit dd6f533

Please sign in to comment.