Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite5afe8f

Browse files
aq-ikhwa-techludomikula
authored andcommitted
Add handling for audit logs feature
1 parent8d0c483 commite5afe8f

File tree

10 files changed

+324
-61
lines changed

10 files changed

+324
-61
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
packageorg.lowcoder.infra.event;
2+
3+
importlombok.Getter;
4+
importlombok.experimental.SuperBuilder;
5+
importorg.springframework.util.MultiValueMap;
6+
7+
@Getter
8+
@SuperBuilder
9+
publicclassAPICallEventextendsAbstractEvent {
10+
11+
privatefinalEventTypetype;
12+
privatefinalStringhttpMethod;
13+
privatefinalStringrequestUri;
14+
privatefinalMultiValueMap<String,String>headers;
15+
privatefinalMultiValueMap<String,String>queryParams;
16+
17+
@Override
18+
publicEventTypegetEventType() {
19+
returnEventType.API_CALL_EVENT;
20+
}
21+
}

‎server/api-service/lowcoder-infra/src/main/java/org/lowcoder/infra/event/AbstractEvent.java‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
packageorg.lowcoder.infra.event;
22

3+
importjava.lang.reflect.Field;
34
importjava.util.HashMap;
45
importjava.util.Map;
56

@@ -14,9 +15,11 @@ public abstract class AbstractEvent implements LowcoderEvent
1415
{
1516
protectedfinalStringorgId;
1617
protectedfinalStringuserId;
17-
protectedMap<String,String>details;
18+
protectedfinalStringsessionHash;
19+
protectedfinalBooleanisAnonymous;
20+
protectedMap<String,Object>details;
1821

19-
publicMap<String,String>details()
22+
publicMap<String,Object>details()
2023
{
2124
returnthis.details;
2225
}
@@ -33,4 +36,20 @@ public B detail(String name, String value)
3336
returnself();
3437
}
3538
}
39+
40+
publicvoidpopulateDetails() {
41+
if (details ==null) {
42+
details =newHashMap<>();
43+
}
44+
for(Fieldf :getClass().getDeclaredFields()){
45+
Objectvalue =null;
46+
try {
47+
f.setAccessible(Boolean.TRUE);
48+
value =f.get(this);
49+
details.put(f.getName(),value);
50+
}catch (Exceptione) {
51+
}
52+
53+
}
54+
}
3655
}

‎server/api-service/lowcoder-server/pom.xml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@
215215
<version>0.11.5</version>
216216
<scope>runtime</scope>
217217
</dependency>
218+
<dependency>
219+
<groupId>org.springframework</groupId>
220+
<artifactId>spring-aspects</artifactId>
221+
</dependency>
218222

219223
</dependencies>
220224

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
packageorg.lowcoder.api.framework.filter;
2+
3+
importorg.springframework.context.annotation.Configuration;
4+
importorg.springframework.http.server.reactive.ServerHttpRequest;
5+
importorg.springframework.web.server.ServerWebExchange;
6+
importorg.springframework.web.server.WebFilter;
7+
importorg.springframework.web.server.WebFilterChain;
8+
importreactor.core.publisher.Mono;
9+
10+
@Configuration
11+
publicclassReactiveRequestContextFilterimplementsWebFilter {
12+
@Override
13+
publicMono<Void>filter(ServerWebExchangeexchange,WebFilterChainchain) {
14+
ServerHttpRequestrequest =exchange.getRequest();
15+
returnchain.filter(exchange)
16+
.contextWrite(ctx ->ctx.put(ReactiveRequestContextHolder.SERVER_HTTP_REQUEST,request));
17+
}
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
packageorg.lowcoder.api.framework.filter;
2+
3+
importorg.springframework.http.server.reactive.ServerHttpRequest;
4+
importreactor.core.publisher.Mono;
5+
6+
publicclassReactiveRequestContextHolder {
7+
publicstaticfinalClass<ServerHttpRequest>SERVER_HTTP_REQUEST =ServerHttpRequest.class;
8+
9+
publicstaticMono<ServerHttpRequest>getRequest() {
10+
returnMono.subscriberContext()
11+
.map(ctx ->ctx.get(SERVER_HTTP_REQUEST));
12+
}
13+
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/plugin/data/PluginServerRequest.java‎

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
packageorg.lowcoder.api.framework.plugin.data;
22

3+
importorg.lowcoder.plugin.api.PluginEndpoint;
4+
importorg.lowcoder.plugin.api.PluginEndpoint.Method;
5+
importorg.lowcoder.plugin.api.data.EndpointRequest;
6+
importorg.springframework.http.HttpCookie;
7+
importorg.springframework.http.HttpHeaders;
8+
importorg.springframework.http.HttpMethod;
9+
importorg.springframework.web.reactive.function.server.ServerRequest;
10+
311
importjava.net.URI;
412
importjava.security.Principal;
513
importjava.util.AbstractMap.SimpleEntry;
@@ -10,14 +18,6 @@
1018
importjava.util.Map.Entry;
1119
importjava.util.concurrent.CompletableFuture;
1220

13-
importorg.lowcoder.plugin.api.PluginEndpoint;
14-
importorg.lowcoder.plugin.api.PluginEndpoint.Method;
15-
importorg.lowcoder.plugin.api.data.EndpointRequest;
16-
importorg.springframework.http.HttpCookie;
17-
importorg.springframework.http.HttpHeaders;
18-
importorg.springframework.http.HttpMethod;
19-
importorg.springframework.web.reactive.function.server.ServerRequest;
20-
2121
publicclassPluginServerRequestimplementsEndpointRequest
2222
{
2323
privateURIuri;
@@ -27,6 +27,8 @@ public class PluginServerRequest implements EndpointRequest
2727
privateMap<String,List<Map.Entry<String,String>>>cookies;
2828
privateMap<String,Object>attributes;
2929
privateMap<String,String>pathVariables;
30+
31+
privateMap<String,List<String>>queryParams;
3032
privateCompletableFuture<?extendsPrincipal>principal;
3133

3234

@@ -36,6 +38,7 @@ public PluginServerRequest()
3638
cookies =newHashMap<>();
3739
attributes =newHashMap<>();
3840
pathVariables =newHashMap<>();
41+
queryParams =newHashMap<>();
3942
}
4043

4144
publicstaticPluginServerRequestfromServerRequest(ServerRequestrequest)
@@ -74,6 +77,14 @@ public static PluginServerRequest fromServerRequest(ServerRequest request)
7477
psr.pathVariables.put(entry.getKey(),entry.getValue());
7578
});
7679
}
80+
81+
if (request.queryParams() !=null)
82+
{
83+
request.queryParams().entrySet()
84+
.forEach(entry -> {
85+
psr.queryParams.put(entry.getKey(),entry.getValue());
86+
});
87+
}
7788

7889
psr.principal =request.principal().toFuture();
7990

@@ -125,6 +136,11 @@ public Map<String, Object> attributes() {
125136
publicMap<String,String>pathVariables() {
126137
returnpathVariables;
127138
}
139+
140+
@Override
141+
publicMap<String,List<String>>queryParams() {
142+
returnqueryParams;
143+
}
128144
@Override
129145
publicCompletableFuture<?extendsPrincipal>principal() {
130146
returnprincipal;

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserService.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public interface SessionUserService {
1818
@NonEmptyMono
1919
Mono<OrgMember>getVisitorOrgMemberCache();
2020

21+
Mono<OrgMember>getVisitorOrgMemberCacheSilent();
22+
2123
Mono<OrgMember>getVisitorOrgMember();
2224

2325
Mono<Boolean>isAnonymousUser();
@@ -33,4 +35,6 @@ public interface SessionUserService {
3335
Mono<User>resolveSessionUserForJWT(Claimsclaims,Stringtoken);
3436

3537
Mono<Boolean>tokenExist(Stringtoken);
38+
39+
Mono<String>getVisitorToken();
3640
}

‎server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/home/SessionUserServiceImpl.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
packageorg.lowcoder.api.home;
22

33
importstaticorg.lowcoder.sdk.constants.GlobalContext.CURRENT_ORG_MEMBER;
4+
importstaticorg.lowcoder.sdk.constants.GlobalContext.VISITOR_TOKEN;
45
importstaticorg.lowcoder.sdk.exception.BizError.UNABLE_TO_FIND_VALID_ORG;
56
importstaticorg.lowcoder.sdk.util.ExceptionUtils.deferredError;
67
importstaticorg.lowcoder.sdk.util.JsonUtils.fromJsonQuietly;
@@ -74,6 +75,17 @@ public Mono<OrgMember> getVisitorOrgMemberCache() {
7475
.switchIfEmpty(deferredError(UNABLE_TO_FIND_VALID_ORG,"UNABLE_TO_FIND_VALID_ORG"));
7576
}
7677

78+
@Override
79+
publicMono<OrgMember>getVisitorOrgMemberCacheSilent() {
80+
returnMono.deferContextual(contextView -> (Mono<OrgMember>)contextView.get(CURRENT_ORG_MEMBER))
81+
.delayUntil(Mono::just);
82+
}
83+
84+
@Override
85+
publicMono<String>getVisitorToken() {
86+
returnMono.deferContextual(contextView ->Mono.just(contextView.get(VISITOR_TOKEN)));
87+
}
88+
7789
@Override
7890
publicMono<OrgMember>getVisitorOrgMember() {
7991
returngetVisitorId()
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
packageorg.lowcoder.api.util;
2+
3+
importcom.google.common.hash.Hashing;
4+
importlombok.extern.slf4j.Slf4j;
5+
importorg.aspectj.lang.ProceedingJoinPoint;
6+
importorg.aspectj.lang.annotation.Around;
7+
importorg.aspectj.lang.annotation.Aspect;
8+
importorg.aspectj.lang.annotation.Pointcut;
9+
importorg.lowcoder.api.framework.filter.ReactiveRequestContextHolder;
10+
importorg.lowcoder.api.home.SessionUserService;
11+
importorg.lowcoder.domain.organization.model.OrgMember;
12+
importorg.lowcoder.infra.event.APICallEvent;
13+
importorg.lowcoder.plugin.api.event.LowcoderEvent.EventType;
14+
importorg.lowcoder.sdk.constants.Authentication;
15+
importorg.springframework.beans.factory.annotation.Autowired;
16+
importorg.springframework.context.ApplicationEventPublisher;
17+
importorg.springframework.http.server.reactive.ServerHttpRequest;
18+
importorg.springframework.stereotype.Component;
19+
importorg.springframework.util.MultiValueMap;
20+
importreactor.core.publisher.Mono;
21+
22+
importjava.nio.charset.StandardCharsets;
23+
24+
importstaticorg.springframework.http.HttpHeaders.writableHttpHeaders;
25+
26+
@Slf4j
27+
@Aspect
28+
@Component
29+
publicclassApiCallEventPublisher {
30+
31+
@Autowired
32+
privateApplicationEventPublisherapplicationEventPublisher;
33+
@Autowired
34+
privateSessionUserServicesessionUserService;
35+
36+
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
37+
publicvoidgetMapping(){}
38+
39+
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
40+
publicvoidpostMapping(){}
41+
42+
@Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)")
43+
publicvoidputMapping(){}
44+
45+
@Pointcut("@annotation(org.springframework.web.bind.annotation.DeleteMapping)")
46+
publicvoiddeleteMapping(){}
47+
48+
@Pointcut("@annotation(org.springframework.web.bind.annotation.PatchMapping)")
49+
publicvoidpatchMapping(){}
50+
51+
@Around("(getMapping() || postMapping() || putMapping() || deleteMapping() || patchMapping())")
52+
publicObjecthandleAPICallEvent(ProceedingJoinPointjoinPoint)throwsThrowable {
53+
54+
returnsessionUserService.getVisitorToken()
55+
.zipWith(sessionUserService.getVisitorOrgMemberCacheSilent().defaultIfEmpty(OrgMember.NOT_EXIST))
56+
.zipWith(ReactiveRequestContextHolder.getRequest())
57+
.doOnNext(
58+
tuple -> {
59+
Stringtoken =tuple.getT1().getT1();
60+
OrgMemberorgMember =tuple.getT1().getT2();
61+
ServerHttpRequestrequest =tuple.getT2();
62+
if (orgMember ==OrgMember.NOT_EXIST) {
63+
return;
64+
}
65+
MultiValueMap<String,String>headers =writableHttpHeaders(request.getHeaders());
66+
headers.remove("Cookie");
67+
headers.remove("X-Real-IP");
68+
APICallEventevent =APICallEvent.builder()
69+
.userId(orgMember.getUserId())
70+
.orgId(orgMember.getOrgId())
71+
.type(EventType.API_CALL_EVENT)
72+
.isAnonymous(Authentication.isAnonymousUser(orgMember.getUserId()))
73+
.sessionHash(Hashing.sha512().hashString(token,StandardCharsets.UTF_8).toString())
74+
.httpMethod(request.getMethod().name())
75+
.requestUri(request.getURI().getPath())
76+
.headers(headers)
77+
.queryParams(request.getQueryParams())
78+
.build();
79+
event.populateDetails();
80+
applicationEventPublisher.publishEvent(event);
81+
})
82+
.onErrorResume(throwable -> {
83+
log.error("handleAPICallEvent error {} for: {} ",joinPoint.getSignature().getName(),EventType.API_CALL_EVENT,throwable);
84+
returnMono.empty();
85+
})
86+
.then((Mono)joinPoint.proceed());
87+
}
88+
89+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp