Commit bdb026b6 by tntxia

安全整改的问题修改

parent 41a1df5a
......@@ -85,6 +85,22 @@
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <!-- JDK 11 推荐用 3.8+ 版本 -->
<configuration>
<!-- 统一为 JDK 11,消除版本不匹配警告 -->
<release>11</release>
<encoding>UTF-8</encoding>
<!-- 可选:关闭严格泛型检查(避免额外报错) -->
<compilerArgs>
<arg>-Xlint:-unchecked</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
......@@ -56,9 +56,71 @@ public class AiInfoServiceImpl extends ServiceImpl<IAiInfoMapper, AiInfoEntity>
String[] arr = param.getOrderBy().split(" ");
String column = arr[0];
String desc = arr.length > 1 ? arr[1] : "desc";
wrapper.last(Objects.nonNull(param.getOrderBy()), " order by " + column + " " + desc);
String direction = arr.length > 1 ? arr[1] : "desc";
// 避免SQL注入,不直接使用SQL语句,所以判断相应的列
switch (column) {
case "id":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getId);
} else {
wrapper.orderByDesc(AiInfoEntity::getId);
}
break;
case "createTime":
case "create_time":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getCreateTime);
} else {
wrapper.orderByDesc(AiInfoEntity::getCreateTime);
}
break;
case "warnTime":
case "warn_time":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getWarnTime);
} else {
wrapper.orderByDesc(AiInfoEntity::getWarnTime);
}
break;
case "deviceSn":
case "device_sn":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getDeviceSn);
} else {
wrapper.orderByDesc(AiInfoEntity::getDeviceSn);
}
break;
case "warnType":
case "warn_type":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getWarnType);
} else {
wrapper.orderByDesc(AiInfoEntity::getWarnType);
}
break;
case "warnEvent":
case "warn_event":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getWarnEvent);
} else {
wrapper.orderByDesc(AiInfoEntity::getWarnEvent);
}
break;
case "algorithmType":
case "algorithm_type":
if ("asc".equals(direction)) {
wrapper.orderByAsc(AiInfoEntity::getAlgorithmType);
} else {
wrapper.orderByDesc(AiInfoEntity::getAlgorithmType);
}
break;
default:
wrapper.orderByDesc(AiInfoEntity::getId);
break;
}
} else {
wrapper.orderByDesc(AiInfoEntity::getId);
}
Page<AiInfoEntity> pagination = this.page(new Page<>(page, pageSize), wrapper);
......
......@@ -32,19 +32,20 @@ public class AuthPrincipalHandler extends DefaultHandshakeHandler {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
String token = servletRequest.getParameter(AuthInterceptor.PARAM_TOKEN);
// 默认让WebSocket的认证都通过
if (!StringUtils.hasText(token)) {
return false;
return true;
}
log.debug("token:" + token);
Optional<CustomClaim> customClaim = JwtUtil.parseToken(token);
if (customClaim.isEmpty()) {
return false;
return true;
}
servletRequest.setAttribute(AuthInterceptor.TOKEN_CLAIM, customClaim.get());
return true;
}
return false;
return true;
}
......@@ -63,6 +64,10 @@ public class AuthPrincipalHandler extends DefaultHandshakeHandler {
CustomClaim claim = (CustomClaim) ((ServletServerHttpRequest) request).getServletRequest()
.getAttribute(AuthInterceptor.TOKEN_CLAIM);
if (claim == null) {
return () -> null;
}
return () -> claim.getWorkspaceId() + "/" + claim.getUserType() + "/" + claim.getId();
}
return () -> null;
......
package com.dji.sample.component.websocket.config;
import com.dji.sample.common.model.CustomClaim;
import com.dji.sample.common.util.JwtUtil;
import com.dji.sample.component.websocket.service.IWebSocketManageService;
import com.dji.sdk.websocket.WebSocketDefaultHandler;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
......@@ -10,6 +14,9 @@ import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import java.security.Principal;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/**
*
......@@ -22,6 +29,10 @@ public class MyWebSocketHandler extends WebSocketDefaultHandler {
private IWebSocketManageService webSocketManageService;
private ObjectMapper objectMapper = new ObjectMapper();
private Map<String, Boolean> authenticatedSessions = new ConcurrentHashMap<>();
private Map<String, CustomClaim> sessionClaims = new ConcurrentHashMap<>();
MyWebSocketHandler(WebSocketHandler delegate, IWebSocketManageService webSocketManageService) {
super(delegate);
this.webSocketManageService = webSocketManageService;
......@@ -30,29 +41,104 @@ public class MyWebSocketHandler extends WebSocketDefaultHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
Principal principal = session.getPrincipal();
if (StringUtils.hasText(principal.getName())) {
webSocketManageService.put(principal.getName(), new MyConcurrentWebSocketSession(session));
log.debug("{} is connected. ID: {}. WebSocketSession[current count: {}]",
principal.getName(), session.getId(), webSocketManageService.getConnectedCount());
return;
String principalName = principal.getName();
if (StringUtils.hasText(principalName) && !principalName.startsWith("temp-")) {
webSocketManageService.put(principalName, new MyConcurrentWebSocketSession(session));
authenticatedSessions.put(session.getId(), true);
log.debug("{} is connected (pre-authenticated). ID: {}. WebSocketSession[current count: {}]",
principalName, session.getId(), webSocketManageService.getConnectedCount());
} else {
log.debug("Unauthenticated connection established. ID: {}, temp principal: {}",
session.getId(), principalName);
}
session.close();
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
Principal principal = session.getPrincipal();
if (StringUtils.hasText(principal.getName())) {
webSocketManageService.remove(principal.getName(), session.getId());
String sessionId = session.getId();
Boolean isAuthenticated = authenticatedSessions.get(sessionId);
if (Boolean.TRUE.equals(isAuthenticated)) {
CustomClaim claim = sessionClaims.get(sessionId);
if (claim != null) {
String key = claim.getWorkspaceId() + "/" + claim.getUserType() + "/" + claim.getId();
webSocketManageService.remove(key, sessionId);
log.debug("{} is disconnected. ID: {}. WebSocketSession[current count: {}]",
principal.getName(), session.getId(), webSocketManageService.getConnectedCount());
key, sessionId, webSocketManageService.getConnectedCount());
}
}
authenticatedSessions.remove(sessionId);
sessionClaims.remove(sessionId);
}
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
log.debug("received message: {}", message.getPayload());
String sessionId = session.getId();
Boolean isAuthenticated = authenticatedSessions.get(sessionId);
String payload = message.getPayload().toString();
log.debug("Received message from session {}: {}", sessionId, payload);
try {
JsonNode jsonNode = objectMapper.readTree(payload);
String type = jsonNode.has("type") ? jsonNode.get("type").asText() : null;
if ("auth".equals(type) && !Boolean.TRUE.equals(isAuthenticated)) {
String token = jsonNode.has("token") ? jsonNode.get("token").asText() : null;
if (StringUtils.hasText(token)) {
Optional<CustomClaim> customClaimOpt = JwtUtil.parseToken(token);
if (customClaimOpt.isPresent()) {
CustomClaim claim = customClaimOpt.get();
String key = claim.getWorkspaceId() + "/" + claim.getUserType() + "/" + claim.getId();
authenticatedSessions.put(sessionId, true);
sessionClaims.put(sessionId, claim);
webSocketManageService.put(key, new MyConcurrentWebSocketSession(session));
log.debug("Session {} authenticated successfully. User: {}", sessionId, key);
String authResponse = objectMapper.writeValueAsString(Map.of(
"type", "auth_success",
"status", "ok"
));
session.sendMessage(new org.springframework.web.socket.TextMessage(authResponse));
return;
}
}
log.warn("Authentication failed for session {}", sessionId);
String authFail = objectMapper.writeValueAsString(Map.of(
"type", "auth_fail",
"status", "error",
"message", "Invalid token"
));
session.sendMessage(new org.springframework.web.socket.TextMessage(authFail));
session.close(CloseStatus.NOT_ACCEPTABLE);
return;
}
if (!Boolean.TRUE.equals(isAuthenticated)) {
log.warn("Unauthenticated session {} tried to send message. Closing.", sessionId);
String authRequired = objectMapper.writeValueAsString(Map.of(
"type", "auth_required",
"message", "Please authenticate first"
));
session.sendMessage(new org.springframework.web.socket.TextMessage(authRequired));
// session.close(CloseStatus.NOT_ACCEPTABLE);
return;
}
super.handleMessage(session, message);
} catch (Exception e) {
log.error("Error handling message from session {}", sessionId, e);
if (!Boolean.TRUE.equals(isAuthenticated)) {
session.close(CloseStatus.BAD_DATA);
}
}
}
}
\ No newline at end of file
......@@ -152,7 +152,7 @@ public class UserController {
}
/**
* Admin resets a user's password.
* User reset password.
* The new password must comply with all password rules.
*
* @param request HTTP request
......@@ -162,6 +162,7 @@ public class UserController {
@PostMapping("/resetPassword")
public HttpResultResponse<Object> resetPassword(HttpServletRequest request,
@RequestBody ChangePasswordParam param) {
CustomClaim customClaim = (CustomClaim) request.getAttribute(TOKEN_CLAIM);
String userId = customClaim.getId();
return userService.resetPassword(userId, param);
......
......@@ -14,10 +14,10 @@ spring:
druid:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://geoair_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true
url: jdbc:mysql://geoair_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
# url: jdbc:mysql://cloud_api_sample_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true
# 深圳
url: jdbc:mysql://cloud_api_sample_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
# url: jdbc:mysql://cloud_api_sample_mysql:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true
username: root
password: root
initial-size: 10
......@@ -26,10 +26,10 @@ spring:
max-wait: 60000
redis:
# host: geoair_redis
host: geoair_redis
# host: cloud_api_sample_redis
# 深圳
host: cloud_api_sample_redis
# host: cloud_api_sample_redis
port: 6379
database: 0
username: # if you enable
......@@ -60,21 +60,23 @@ jwt:
age: 86400
mqtt:
# @see com.dji.sample.component.mqtt.model.MqttUseEnum
# BASIC parameters are required.
NET:
# protocol: MQTT # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum
# host: 183.11.236.162
# port: 54418
# username: JavaServer
# password: 123456
# client-id: 123456
# protocol: MQTT # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum
# host: 183.11.236.162
# port: 54418
# username: JavaServer
# password: 123456
# client-id: 123456
protocol: WSS
host: geofly.geotwin.cn
host: geofly.geotwin.cc
port: 443
path: /mqtt
username: JavaServer
password: 123456
# @see com.dji.sample.component.mqtt.model.MqttUseEnum
# BASIC parameters are required.
BASIC:
protocol: MQTT # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum
# 深圳
......@@ -84,10 +86,10 @@ mqtt:
# host: emqx-broker
# host: 192.168.32.90
# port: 44418
# host: 203.186.109.106
# port: 54941
host: emqx-broker
port: 1883
host: 203.186.109.106
port: 54941
# host: emqx-broker
# port: 1883
username: JavaServer
password: 123456
client-id: 123456
......@@ -95,16 +97,16 @@ mqtt:
path:
DRC:
# 深圳
protocol: WSS
host: geofly.geotwin.cn
port: 443
# protocol: WSS # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum
# protocol: WS
# host: 183.11.236.162
# port: 54419
protocol: WSS # @see com.dji.sample.component.mqtt.model.MqttProtocolEnum
# host: emqx-broker
# host: 192.168.32.90
# port: 8083
# host: geofly-dev.geotwin.cc
# host: geofly.geotwin.cc
# port: 443
host: geofly.geotwin.cc
port: 443
path: /mqtt
username: JavaServer
password: 123456
......@@ -112,7 +114,7 @@ mqtt:
cloud-sdk:
mqtt:
# Topics that need to be subscribed when initially connecting to mqtt, multiple topics are divided by ",".
inbound-topic: sys/product/+/status,thing/product/+/requests,thing/product/+/osd,/ai_info
inbound-topic: sys/product/+/status,thing/product/+/requests,/ai_info
url:
manage:
......@@ -167,10 +169,9 @@ url:
oss:
enable: true
provider: minio
# 香港
# endpoint: https://gt7-oss.geotwin.cc
endpoint: https://gt7-oss.geotwin.cc
# 深圳
endpoint: https://gt-oss-dev.geotwin.cn
# endpoint: https://gt-oss-dev.geotwin.cn
access-key: minioadmin
secret-key: minioadmin
bucket: gtfly
......@@ -211,10 +212,9 @@ livestream:
# RTMP Note: This IP is the address of the streaming server. If you want to see livestream on web page, you need to convert the RTMP stream to WebRTC stream.
rtmp:
# url: rtmp://203.186.109.106:44424/live/ # Example: 'rtmp://192.168.1.1/live/'
url: rtmp://203.186.109.106:44424/live/ # Example: 'rtmp://192.168.1.1/live/'
# 深圳
# url: rtmp://183.11.236.162:54424/live/ # Example: 'rtmp://192.168.1.1/live/'
url: rtmp://183.11.236.162:54460/live/ # Example: 'rtmp://192.168.1.1/live/'
rtsp:
username: Please enter the username.
password: Please enter the password.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment