review code.

This commit is contained in:
lijiahang
2023-07-14 18:11:37 +08:00
parent e0fc9171b6
commit 97b4a27033
19 changed files with 212 additions and 56 deletions

View File

@@ -16,4 +16,12 @@ public class Const implements com.orion.lang.constant.Const {
public static final Integer IS_DELETED = 1; public static final Integer IS_DELETED = 1;
public static final int BEARER_PREFIX_LEN = 7;
public static final int MD5_LEN = 32;
public static final String UNKNOWN = "未知";
public static final String INTRANET_IP = "内网IP";
} }

View File

@@ -13,10 +13,16 @@ public interface ErrorMessage {
String ID_MISSING = "id 不能为空"; String ID_MISSING = "id 不能为空";
String USERNAME_PASSWORD_ERROR = "用户名或密码错误";
String DATA_PRESENT = "数据已存在"; String DATA_PRESENT = "数据已存在";
String DATA_ABSENT = "数据不存在"; String DATA_ABSENT = "数据不存在";
String USERNAME_PASSWORD_ERROR = "用户名或密码错误";
String MAX_LOGIN_FAILED = "登陆失败次数已上限";
String USER_DISABLED = "用户已被禁用";
String USER_LOCKED = "用户已被锁定";
} }

View File

@@ -1,5 +1,6 @@
package com.orion.ops.framework.common.crypto; package com.orion.ops.framework.common.crypto;
import com.orion.lang.utils.codec.Base62s;
import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto; import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto;
/** /**
@@ -16,4 +17,24 @@ public interface ValueCrypto extends SymmetricCrypto {
*/ */
void init(); void init();
/**
* 加密后 base62 编码
*
* @param plain 明文
* @return 密文
*/
default String encryptBase62(String plain) {
return new String(Base62s.encode(this.encrypt(plain)));
}
/**
* base62 解码后解密
*
* @param text 密文
* @return 明文
*/
default String decryptBase62(String text) {
return new String(this.decrypt(Base62s.decode(text)));
}
} }

View File

@@ -1,5 +1,6 @@
package com.orion.ops.framework.common.security; package com.orion.ops.framework.common.security;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@@ -12,26 +13,25 @@ import java.util.List;
* @since 2023/7/6 18:36 * @since 2023/7/6 18:36
*/ */
@Data @Data
@Schema(name = "LoginUser", description = "当前登录用户对象")
public class LoginUser { public class LoginUser {
/** @Schema(description = "id")
* id
*/
private Long id; private Long id;
/** @Schema(description = "用户名")
* 用户名
*/
private String username; private String username;
/** @Schema(description = "花名")
* 花名
*/
private String nickname; private String nickname;
/** @Schema(description = "用户状态")
* 角色 private Integer status;
*/
@Schema(description = "头像地址")
private String avatar;
@Schema(description = "角色")
private List<String> roles; private List<String> roles;
} }

View File

@@ -1,6 +1,6 @@
package com.orion.ops.framework.common.utils; package com.orion.ops.framework.common.utils;
import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto; import com.orion.ops.framework.common.crypto.ValueCrypto;
/** /**
* 加密工具类 * 加密工具类
@@ -11,10 +11,7 @@ import com.orion.lang.utils.crypto.symmetric.SymmetricCrypto;
*/ */
public class CryptoUtils { public class CryptoUtils {
/** private static ValueCrypto delegate;
* 加密器 供 framework 赋值
*/
public static SymmetricCrypto delegate;
/** /**
* 加密 * 加密
@@ -118,4 +115,28 @@ public class CryptoUtils {
return delegate.verify(plain, text); return delegate.verify(plain, text);
} }
/**
* 加密后 base62 编码
*
* @param plain 明文
* @return 密文
*/
public static String encryptBase62(String plain) {
return delegate.encryptBase62(plain);
}
/**
* base62 解码后解密
*
* @param text 密文
* @return 明文
*/
public static String decryptBase62(String text) {
return delegate.decryptBase62(text);
}
public static void setDelegate(ValueCrypto delegate) {
CryptoUtils.delegate = delegate;
}
} }

View File

@@ -0,0 +1,54 @@
package com.orion.ops.framework.common.utils;
import com.orion.ext.location.Region;
import com.orion.ext.location.region.LocationRegions;
import com.orion.ops.framework.common.constant.Const;
/**
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/14 16:26
*/
public class IpUtils {
private IpUtils() {
}
/**
* 获取 ip 位置
*
* @param ip ip
* @return ip 位置
*/
public static String getLocation(String ip) {
if (ip == null) {
return Const.UNKNOWN;
}
Region region;
try {
region = LocationRegions.getRegion(ip, 3);
} catch (Exception e) {
return Const.UNKNOWN;
}
if (region != null) {
String net = region.getNet();
String province = region.getProvince();
if (net.equals(Const.INTRANET_IP)) {
return net;
}
if (province.equals(Const.UNKNOWN)) {
return province;
}
StringBuilder location = new StringBuilder()
.append(region.getCountry())
.append(Const.DASHED)
.append(province)
.append(Const.DASHED)
.append(region.getCity());
location.append(" (").append(net).append(')');
return location.toString();
}
return Const.UNKNOWN;
}
}

View File

@@ -0,0 +1,34 @@
package com.orion.ops.framework.common.utils;
import com.orion.lang.utils.Strings;
import com.orion.ops.framework.common.constant.Const;
/**
* 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/7/14 16:34
*/
public class Kits {
private Kits() {
}
/**
* 获取登陆凭证
*
* @param authorization authorization
* @return token
*/
public static String getAuthorization(String authorization) {
if (Strings.isEmpty(authorization)) {
return null;
}
if (!authorization.contains(Const.BEARER) || authorization.length() <= Const.BEARER_PREFIX_LEN) {
return null;
}
return authorization.substring(Const.BEARER_PREFIX_LEN).trim();
}
}

View File

@@ -64,21 +64,29 @@ public class DataQuery<T> {
return this; return this;
} }
public Optional<T> get() { public T get() {
return dao.selectOne(wrapper);
}
public Optional<T> optional() {
return Optional.ofNullable(dao.selectOne(wrapper)); return Optional.ofNullable(dao.selectOne(wrapper));
} }
public <R> Optional<R> get(Function<T, R> mapper) { public <R> Optional<R> optional(Function<T, R> mapper) {
Valid.notNull(mapper, "convert function is null"); Valid.notNull(mapper, "convert function is null");
return Optional.ofNullable(dao.selectOne(wrapper)) return Optional.ofNullable(dao.selectOne(wrapper))
.map(mapper); .map(mapper);
} }
public Stream<T> list() { public List<T> list() {
return dao.selectList(wrapper);
}
public Stream<T> stream() {
return dao.selectList(wrapper).stream(); return dao.selectList(wrapper).stream();
} }
public <R> List<R> list(Function<T, R> mapper) { public <R> List<R> stream(Function<T, R> mapper) {
Valid.notNull(mapper, "convert function is null"); Valid.notNull(mapper, "convert function is null");
return Lists.map(dao.selectList(wrapper), mapper); return Lists.map(dao.selectList(wrapper), mapper);
} }

View File

@@ -16,14 +16,13 @@ import java.util.List;
* @since ${date} * @since ${date}
*/ */
@Mapper @Mapper
@SuppressWarnings("ALL")
public interface ${type}ProviderConvert { public interface ${type}ProviderConvert {
${type}ProviderConvert MAPPER = Mappers.getMapper(${type}ProviderConvert.class); ${type}ProviderConvert MAPPER = Mappers.getMapper(${type}ProviderConvert.class);
${type}DO to(${type}DTO dto); ${type}DO to(${type}DTO dto);
${type}DTO to(${type}DO dto); ${type}DTO to(${type}DO domain);
List<${type}DO> toDO(List<${type}DTO> list); List<${type}DO> toDO(List<${type}DTO> list);

View File

@@ -16,7 +16,6 @@ import java.util.List;
* @since ${date} * @since ${date}
*/ */
@Mapper @Mapper
@SuppressWarnings("ALL")
public interface ${type}Convert { public interface ${type}Convert {
${type}Convert MAPPER = Mappers.getMapper(${type}Convert.class); ${type}Convert MAPPER = Mappers.getMapper(${type}Convert.class);
@@ -27,7 +26,7 @@ public interface ${type}Convert {
${type}DO to(${type}QueryRequest request); ${type}DO to(${type}QueryRequest request);
${type}VO to(${type}DO request); ${type}VO to(${type}DO domain);
List<${type}VO> to(List<${type}DO> list); List<${type}VO> to(List<${type}DO> list);

View File

@@ -37,9 +37,9 @@ public class OrionRedisAutoConfiguration {
RedisTemplate<String, T> redisTemplate = new RedisTemplate<>(); RedisTemplate<String, T> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(RedisSerializer.string()); redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(RedisSerializer.json()); redisTemplate.setValueSerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string()); redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(RedisSerializer.json()); redisTemplate.setHashValueSerializer(RedisSerializer.string());
redisTemplate.afterPropertiesSet(); redisTemplate.afterPropertiesSet();
return redisTemplate; return redisTemplate;
} }

View File

@@ -2,14 +2,12 @@ package com.orion.ops.framework.security.config;
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst; import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
import com.orion.ops.framework.common.crypto.ValueCrypto; import com.orion.ops.framework.common.crypto.ValueCrypto;
import com.orion.ops.framework.common.utils.CryptoUtils;
import com.orion.ops.framework.security.core.crypto.aes.AesCryptoProcessor; import com.orion.ops.framework.security.core.crypto.aes.AesCryptoProcessor;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -31,14 +29,10 @@ public class OrionCryptoAutoConfiguration {
/** /**
* @return aes 加密器 * @return aes 加密器
*/ */
@Primary
@Bean(initMethod = "init") @Bean(initMethod = "init")
@ConditionalOnProperty(value = "orion.crypto.aes.enabled", havingValue = "true") @ConditionalOnProperty(value = "orion.crypto.aes.enabled", havingValue = "true")
public ValueCrypto aes() { public ValueCrypto aes() {
ValueCrypto processor = new AesCryptoProcessor(config.getAes()); return new AesCryptoProcessor(config.getAes());
// 设置工具委托类 委托需要与 @Primary 相同, 否则会导致工具类和bean的结果不同
CryptoUtils.delegate = processor;
return processor;
} }
} }

View File

@@ -12,6 +12,11 @@ import lombok.Data;
@Data @Data
public class CryptoConfig { public class CryptoConfig {
/**
* 是否为默认加密器
*/
protected boolean primary;
/** /**
* 是否启用 * 是否启用
*/ */

View File

@@ -1,6 +1,7 @@
package com.orion.ops.framework.security.core.crypto; package com.orion.ops.framework.security.core.crypto;
import com.orion.ops.framework.common.crypto.ValueCrypto; import com.orion.ops.framework.common.crypto.ValueCrypto;
import com.orion.ops.framework.common.utils.CryptoUtils;
/** /**
* 数据加密器 * 数据加密器
@@ -15,6 +16,10 @@ public abstract class CryptoProcessor<Config extends CryptoConfig> implements Va
protected CryptoProcessor(Config config) { protected CryptoProcessor(Config config) {
this.config = config; this.config = config;
// 设置为默认加密器
if (config.isPrimary()) {
CryptoUtils.setDelegate(this);
}
} }
/** /**

View File

@@ -88,6 +88,8 @@ public class PermitAllAnnotationAuthorizeRequestsCustomizer extends AuthorizeReq
case DELETE: case DELETE:
deleteList.addAll(urls); deleteList.addAll(urls);
break; break;
default:
break;
} }
}); });
}); });

View File

@@ -1,9 +1,8 @@
package com.orion.ops.framework.security.core.utils; package com.orion.ops.framework.security.core.utils;
import com.orion.lang.constant.StandardHttpHeader; import com.orion.lang.constant.StandardHttpHeader;
import com.orion.lang.utils.Strings;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.security.LoginUser; import com.orion.ops.framework.common.security.LoginUser;
import com.orion.ops.framework.common.utils.Kits;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
@@ -22,8 +21,6 @@ import java.util.Collections;
*/ */
public class SecurityUtils { public class SecurityUtils {
private static final int BEARER_PREFIX_LEN = 7;
private SecurityUtils() { private SecurityUtils() {
} }
@@ -34,14 +31,7 @@ public class SecurityUtils {
* @return token * @return token
*/ */
public static String obtainAuthorization(HttpServletRequest request) { public static String obtainAuthorization(HttpServletRequest request) {
String authorization = request.getHeader(StandardHttpHeader.AUTHORIZATION); return Kits.getAuthorization(request.getHeader(StandardHttpHeader.AUTHORIZATION));
if (Strings.isEmpty(authorization)) {
return null;
}
if (!authorization.contains(Const.BEARER) || authorization.length() <= BEARER_PREFIX_LEN) {
return null;
}
return authorization.substring(BEARER_PREFIX_LEN).trim();
} }
/** /**

View File

@@ -28,6 +28,12 @@
"type": "java.util.List", "type": "java.util.List",
"description": "匿名接口." "description": "匿名接口."
}, },
{
"name": "orion.crypto.primary.enabled",
"type": "java.lang.Boolean",
"description": "是否为默认加密器.",
"defaultValue": "false"
},
{ {
"name": "orion.crypto.aes.enabled", "name": "orion.crypto.aes.enabled",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",

View File

@@ -67,27 +67,30 @@ public class GlobalExceptionHandler {
@ExceptionHandler(value = MissingServletRequestParameterException.class) @ExceptionHandler(value = MissingServletRequestParameterException.class)
public HttpWrapper<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) { public HttpWrapper<?> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException ex) {
log.error("missingServletRequestParameterExceptionHandler", ex); String message = Strings.format(ErrorMessage.PARAM_MISSING, ex.getParameterName());
return ErrorCode.BAD_REQUEST.wrapper().msg(Strings.format(ErrorMessage.PARAM_MISSING, ex.getParameterName())); log.error("missingServletRequestParameterExceptionHandler {}", message);
return ErrorCode.BAD_REQUEST.wrapper().msg(message);
} }
@ExceptionHandler(value = BindException.class) @ExceptionHandler(value = BindException.class)
public HttpWrapper<?> paramBindExceptionHandler(BindException ex) { public HttpWrapper<?> paramBindExceptionHandler(BindException ex) {
log.error("paramBindExceptionHandler", ex);
FieldError error = Objects.requireNonNull(ex.getFieldError()); FieldError error = Objects.requireNonNull(ex.getFieldError());
return ErrorCode.BAD_REQUEST.wrapper().msg(error.getField() + " " + error.getDefaultMessage()); String message = error.getField() + " " + error.getDefaultMessage();
log.error("paramBindExceptionHandler {}", message);
return ErrorCode.BAD_REQUEST.wrapper().msg(message);
} }
@ExceptionHandler(value = ConstraintViolationException.class) @ExceptionHandler(value = ConstraintViolationException.class)
public HttpWrapper<?> constraintViolationExceptionHandler(ConstraintViolationException ex) { public HttpWrapper<?> constraintViolationExceptionHandler(ConstraintViolationException ex) {
log.error("constraintViolationExceptionHandler", ex);
ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next(); ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
return ErrorCode.BAD_REQUEST.wrapper().msg(Objects.requireNonNull(constraintViolation).getMessage()); String message = Objects.requireNonNull(constraintViolation).getMessage();
log.error("constraintViolationExceptionHandler {}", message);
return ErrorCode.BAD_REQUEST.wrapper().msg(message);
} }
@ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class}) @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
public HttpWrapper<?> httpRequestMethodNotSupportedExceptionHandler(Exception ex) { public HttpWrapper<?> httpRequestMethodNotSupportedExceptionHandler(Exception ex) {
log.error("httpRequestMethodNotSupportedExceptionHandler", ex); log.error("httpRequestMethodNotSupportedExceptionHandler {}", ex.getMessage());
return ErrorCode.METHOD_NOT_ALLOWED.getWrapper(); return ErrorCode.METHOD_NOT_ALLOWED.getWrapper();
} }
@@ -118,7 +121,7 @@ public class GlobalExceptionHandler {
IllegalArgumentException.class IllegalArgumentException.class
}) })
public HttpWrapper<?> invalidArgumentExceptionHandler(Exception ex) { public HttpWrapper<?> invalidArgumentExceptionHandler(Exception ex) {
log.error("invalidArgumentExceptionHandler", ex); log.error("invalidArgumentExceptionHandler {}", ex.getMessage());
return ErrorCode.BAD_REQUEST.wrapper().msg(ex.getMessage()); return ErrorCode.BAD_REQUEST.wrapper().msg(ex.getMessage());
} }

View File

@@ -178,6 +178,7 @@ orion:
crypto: crypto:
# aes加密器 # aes加密器
aes: aes:
primary: true
enabled: true enabled: true
working-mode: ECB working-mode: ECB
padding-mode: PKCS5_PADDING padding-mode: PKCS5_PADDING