Compare commits
2 Commits
ae4599cd9a
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 2869994387 | |||
| 287b124f7e |
@@ -8,10 +8,13 @@ import org.springframework.security.authentication.ProviderManager;
|
|||||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import quant.rich.emoney.service.AuthService;
|
import quant.rich.emoney.service.AuthService;
|
||||||
@@ -27,10 +30,10 @@ public class SecurityConfig {
|
|||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
http
|
http
|
||||||
.headers(headers -> headers
|
.headers(headers -> headers
|
||||||
.cacheControl(cache -> cache.disable())
|
.cacheControl(HeadersConfigurer.CacheControlConfig::disable)
|
||||||
.frameOptions(f -> f.sameOrigin())
|
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
|
||||||
)
|
)
|
||||||
.csrf(csrf -> csrf.disable())
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/favicon.ico").permitAll()
|
.requestMatchers("/favicon.ico").permitAll()
|
||||||
.requestMatchers("/admin/*/login").permitAll()
|
.requestMatchers("/admin/*/login").permitAll()
|
||||||
@@ -41,11 +44,8 @@ public class SecurityConfig {
|
|||||||
.requestMatchers("/img/**").permitAll()
|
.requestMatchers("/img/**").permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.formLogin(form -> form // 开启表单登录,并指定登录页
|
.exceptionHandling(ex -> ex
|
||||||
.loginPage("/admin/v1/login") // 指定登录页
|
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/admin/v1/login")))
|
||||||
.loginProcessingUrl("/admin/v1/doLogin") // 处理登录请求的 URL
|
|
||||||
.defaultSuccessUrl("/admin/v1/", false) // 登录成功后默认跳转
|
|
||||||
.permitAll())
|
|
||||||
.logout(logout -> logout
|
.logout(logout -> logout
|
||||||
.logoutUrl("/admin/v1/logout")
|
.logoutUrl("/admin/v1/logout")
|
||||||
.logoutSuccessUrl("/admin/v1/login")
|
.logoutSuccessUrl("/admin/v1/login")
|
||||||
@@ -54,7 +54,6 @@ public class SecurityConfig {
|
|||||||
.sessionManagement(session -> session
|
.sessionManagement(session -> session
|
||||||
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
|
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
|
||||||
);
|
);
|
||||||
;
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
@@ -53,7 +52,7 @@ public class RequestInfoControllerV1 extends UpdateBoolServiceController<Request
|
|||||||
|
|
||||||
@PostMapping("/save")
|
@PostMapping("/save")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public R<?> save(@RequestBody @NonNull RequestInfo requestInfo) {
|
public R<?> save(@RequestBody @Valid @NonNull RequestInfo requestInfo) {
|
||||||
return super.save(requestInfo);
|
return super.save(requestInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,18 +80,11 @@ public class RequestInfoControllerV1 extends UpdateBoolServiceController<Request
|
|||||||
return R.judge(getThisService().removeByIds(idArray));
|
return R.judge(getThisService().removeByIds(idArray));
|
||||||
}
|
}
|
||||||
|
|
||||||
LambdaUpdateWrapper<RequestInfo> uw = new LambdaUpdateWrapper<>();
|
|
||||||
uw.in(RequestInfo::getId, idArray);
|
|
||||||
switch (op) {
|
|
||||||
default:
|
|
||||||
throw RException.badRequest("未知操作");
|
throw RException.badRequest("未知操作");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static enum RequestInfoBatchOp {
|
private static enum RequestInfoBatchOp {
|
||||||
DELETE,
|
DELETE
|
||||||
ENABLE_ANONYMOUS,
|
|
||||||
DISABLE_ANONYMOUS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import org.apache.commons.lang3.ObjectUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||||
@@ -12,10 +11,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import quant.rich.emoney.entity.config.AndroidSdkLevelConfig;
|
import quant.rich.emoney.entity.config.AndroidSdkLevelConfig;
|
||||||
@@ -28,15 +25,21 @@ import quant.rich.emoney.util.TextUtils;
|
|||||||
import quant.rich.emoney.validator.RequestInfoValid;
|
import quant.rich.emoney.validator.RequestInfoValid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用于配置请求时的请求行为,一般而言,请求头与安卓系统的信息有关(build.prop)
|
* <b>请求信息</b>
|
||||||
* 虽然部分请求对应服务器可能不进行审核,但合理的请求头能尽可能模仿真机行为,避免风险
|
* <p>
|
||||||
* @see DeviceInfoConfig
|
* 用于配置请求时的参数,包括请求头等。若使用该请求头登录成功,则将会存储鉴权信息。
|
||||||
* @see AndroidSdkLevelConfig
|
*
|
||||||
* @see ChromeVersionsConfig
|
* 一般而言,请求头与系统的信息有关(build.prop)
|
||||||
|
* 虽然服务器可能不进行请求头审核,但合理的请求头能尽可能模仿真机行为,避免风险。
|
||||||
* <p>
|
* <p>
|
||||||
* SQLite 表 request_info 使用触发器维护默认请求配置的一致性:新增或更新 is_default = 1
|
* SQLite 表 request_info 使用触发器维护默认请求配置的一致性:新增或更新 is_default = 1
|
||||||
* 时会把其他记录置为非默认;不允许把最后一条默认请求配置改为非默认,也不允许删除默认请求配置。
|
* 时会把其他记录置为非默认;不允许把最后一条默认请求配置改为非默认,也不允许删除默认请求配置。
|
||||||
* 这部分约束不在 Java 代码里重复实现,调整表结构或导入数据时需要同步检查触发器。
|
* 这部分约束不在 Java 代码里重复实现,调整表结构或导入数据时需要同步检查触发器。
|
||||||
|
*
|
||||||
|
* @see DeviceInfoConfig
|
||||||
|
* @see AndroidSdkLevelConfig
|
||||||
|
* @see ChromeVersionsConfig
|
||||||
|
* @See RequestInfoValidator
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper=false)
|
@EqualsAndHashCode(callSuper=false)
|
||||||
@@ -113,9 +116,10 @@ public class RequestInfo extends Model<RequestInfo> {
|
|||||||
* @see DeviceInfoConfig
|
* @see DeviceInfoConfig
|
||||||
* @see DeviceInfo
|
* @see DeviceInfo
|
||||||
*/
|
*/
|
||||||
@Setter(AccessLevel.PRIVATE)
|
public String getAndroidVersion() {
|
||||||
@TableField(exist=false)
|
DeviceInfo deviceInfo = getDeviceInfo();
|
||||||
private String androidVersion;
|
return deviceInfo == null ? null : deviceInfo.getVersionRelease();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>用于:</b><ul>
|
* <b>用于:</b><ul>
|
||||||
@@ -127,9 +131,13 @@ public class RequestInfo extends Model<RequestInfo> {
|
|||||||
* @see DeviceInfo
|
* @see DeviceInfo
|
||||||
* @see AndroidSdkLevelConfig
|
* @see AndroidSdkLevelConfig
|
||||||
*/
|
*/
|
||||||
@Setter(AccessLevel.PRIVATE)
|
public String getAndroidSdkLevel() {
|
||||||
@TableField(exist=false)
|
String androidVersion = getAndroidVersion();
|
||||||
private String androidSdkLevel;
|
if (StringUtils.isBlank(androidVersion)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return String.valueOf(androidSdkLevelConfig.getSdkLevel(androidVersion));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>用于:</b><ul>
|
* <b>用于:</b><ul>
|
||||||
@@ -183,8 +191,10 @@ public class RequestInfo extends Model<RequestInfo> {
|
|||||||
* @see DeviceInfoConfig
|
* @see DeviceInfoConfig
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@TableField(exist=false)
|
public String getBuildId() {
|
||||||
private String buildId;
|
DeviceInfo deviceInfo = getDeviceInfo();
|
||||||
|
return deviceInfo == null ? null : deviceInfo.getBuildId();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>用于:</b><ul>
|
* <b>用于:</b><ul>
|
||||||
@@ -218,21 +228,29 @@ public class RequestInfo extends Model<RequestInfo> {
|
|||||||
/**
|
/**
|
||||||
* 从 deviceInfo 设置相关字段
|
* 从 deviceInfo 设置相关字段
|
||||||
* @param deviceInfo
|
* @param deviceInfo
|
||||||
* @return
|
* @return 更新过的 RequestInfo 本身
|
||||||
*/
|
*/
|
||||||
public RequestInfo setRelativeFieldsFromDeviceInfo(DeviceInfo deviceInfo) {
|
public RequestInfo setRelativeFieldsFromDeviceInfo(DeviceInfo deviceInfo) {
|
||||||
if (deviceInfo == null) {
|
if (deviceInfo == null) {
|
||||||
throw new NullPointerException("deviceInfo is null");
|
throw new NullPointerException("deviceInfo is null");
|
||||||
}
|
}
|
||||||
deviceName = deviceInfo.getModel();
|
deviceName = deviceInfo.getModel();
|
||||||
androidVersion = deviceInfo.getVersionRelease();
|
|
||||||
androidSdkLevel = String.valueOf(androidSdkLevelConfig.getSdkLevel(androidVersion));
|
|
||||||
softwareType = deviceInfo.getDeviceType();
|
softwareType = deviceInfo.getDeviceType();
|
||||||
fingerprint = deviceInfo.getFingerprint();
|
fingerprint = deviceInfo.getFingerprint();
|
||||||
buildId = deviceInfo.getBuildId();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 获取由相应字段指定的 DeviceInfo
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
private DeviceInfo getDeviceInfo() {
|
||||||
|
if (ObjectUtils.anyNull(deviceName, fingerprint, softwareType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return DeviceInfo.from(deviceName, fingerprint, softwareType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置密码:<ul>
|
* 设置密码:<ul>
|
||||||
* <li>null or empty,保存空字符串</li>
|
* <li>null or empty,保存空字符串</li>
|
||||||
@@ -264,13 +282,7 @@ public class RequestInfo extends Model<RequestInfo> {
|
|||||||
* @see RequestInfo#setRelativeFieldsFromDeviceInfo
|
* @see RequestInfo#setRelativeFieldsFromDeviceInfo
|
||||||
*/
|
*/
|
||||||
public RequestInfo setFingerprint(String fingerprint) {
|
public RequestInfo setFingerprint(String fingerprint) {
|
||||||
if (ObjectUtils.allNotNull(deviceName, softwareType, fingerprint, androidSdkLevelConfig)) {
|
|
||||||
DeviceInfo deviceInfo = DeviceInfo.from(deviceName, fingerprint, softwareType);
|
|
||||||
setRelativeFieldsFromDeviceInfo(deviceInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.fingerprint = fingerprint;
|
this.fingerprint = fingerprint;
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class RequestInfoService extends SqliteServiceImpl<RequestInfoMapper, Req
|
|||||||
);
|
);
|
||||||
if (requestInfo == null) {
|
if (requestInfo == null) {
|
||||||
requestInfo = new RequestInfo();
|
requestInfo = new RequestInfo();
|
||||||
|
requestInfo.setIsDefault(true);
|
||||||
save(requestInfo);
|
save(requestInfo);
|
||||||
}
|
}
|
||||||
return requestInfo;
|
return requestInfo;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import jakarta.validation.Payload;
|
|||||||
@Target({ ElementType.TYPE })
|
@Target({ ElementType.TYPE })
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface RequestInfoValid {
|
public @interface RequestInfoValid {
|
||||||
String message() default "非法的 EmoneyRequestConfig";
|
String message() default "非法的 RequestInfo";
|
||||||
Class<?>[] groups() default {};
|
Class<?>[] groups() default {};
|
||||||
Class<? extends Payload>[] payload() default {};
|
Class<? extends Payload>[] payload() default {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import quant.rich.emoney.entity.config.DeviceInfoConfig;
|
|||||||
import quant.rich.emoney.entity.sqlite.RequestInfo;
|
import quant.rich.emoney.entity.sqlite.RequestInfo;
|
||||||
import quant.rich.emoney.interfaces.IValidator;
|
import quant.rich.emoney.interfaces.IValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RequestInfo 校验器
|
||||||
|
*/
|
||||||
public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> {
|
public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> {
|
||||||
|
|
||||||
static final Pattern androidIdPattern = Pattern.compile("^[0-9a-f]{16}$");
|
static final Pattern androidIdPattern = Pattern.compile("^[0-9a-f]{16}$");
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$(non).children('label').children('span').remove();
|
$(non).children('label').children('span').remove();
|
||||||
$(non).find('lay-verify').removeAttr('lay-verify');
|
$(non).find('[lay-verify]').removeAttr('lay-verify');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,9 +58,7 @@
|
|||||||
Helper.renderDropdown({
|
Helper.renderDropdown({
|
||||||
elem: '.operdown',
|
elem: '.operdown',
|
||||||
data: [
|
data: [
|
||||||
{title: '删除', op: 'DELETE'},
|
{title: '删除', op: 'DELETE'}],
|
||||||
{title: '开启匿名', op: 'ENABLE_ANONYMOUS'},
|
|
||||||
{title: '关闭匿名', op: 'DISABLE_ANONYMOUS'}],
|
|
||||||
tableFilter: 'requestInfos',
|
tableFilter: 'requestInfos',
|
||||||
url: '/admin/v1/manage/requestInfo/batchOp',
|
url: '/admin/v1/manage/requestInfo/batchOp',
|
||||||
idName: 'id'
|
idName: 'id'
|
||||||
|
|||||||
Reference in New Issue
Block a user