11package org .lowcoder .api .framework .filter ;
22
33import lombok .extern .slf4j .Slf4j ;
4+ import org .apache .commons .lang3 .tuple .Triple ;
45import org .lowcoder .api .authentication .request .AuthRequest ;
56import org .lowcoder .api .authentication .request .AuthRequestFactory ;
67import org .lowcoder .api .authentication .request .oauth2 .OAuth2RequestContext ;
78import org .lowcoder .api .authentication .service .AuthenticationApiServiceImpl ;
89import org .lowcoder .api .home .SessionUserService ;
910import org .lowcoder .domain .authentication .AuthenticationService ;
10- import org .lowcoder .domain .authentication .FindAuthConfig ;
1111import org .lowcoder .domain .authentication .context .AuthRequestContext ;
1212import org .lowcoder .domain .user .model .AuthUser ;
13+ import org .lowcoder .domain .user .model .Connection ;
14+ import org .lowcoder .domain .user .model .User ;
15+ import org .lowcoder .domain .user .service .UserService ;
1316import org .lowcoder .sdk .util .CookieHelper ;
1417import org .springframework .web .server .ServerWebExchange ;
1518import org .springframework .web .server .WebFilter ;
1821
1922import javax .annotation .Nonnull ;
2023import java .time .Instant ;
21- import java .util .LinkedList ;
22- import java .util .List ;
24+ import java .util .Optional ;
2325
2426import static org .lowcoder .api .authentication .util .AuthenticationUtils .toAuthentication ;
2527import static org .lowcoder .domain .authentication .AuthenticationService .DEFAULT_AUTH_CONFIG ;
2931public class UserSessionPersistenceFilter implements WebFilter {
3032
3133 private final SessionUserService service ;
34+
35+ private final UserService userService ;
3236 private final CookieHelper cookieHelper ;
3337
3438 private final AuthenticationService authenticationService ;
@@ -37,9 +41,10 @@ public class UserSessionPersistenceFilter implements WebFilter {
3741
3842 private final AuthRequestFactory <AuthRequestContext > authRequestFactory ;
3943
40- public UserSessionPersistenceFilter (SessionUserService service , CookieHelper cookieHelper , AuthenticationService authenticationService ,
44+ public UserSessionPersistenceFilter (SessionUserService service , UserService userService , CookieHelper cookieHelper , AuthenticationService authenticationService ,
4145 AuthenticationApiServiceImpl authenticationApiService , AuthRequestFactory <AuthRequestContext > authRequestFactory ) {
4246 this .service = service ;
47+ this .userService = userService ;
4348 this .cookieHelper = cookieHelper ;
4449 this .authenticationService = authenticationService ;
4550 this .authenticationApiService = authenticationApiService ;
@@ -52,48 +57,88 @@ public Mono<Void> filter(@Nonnull ServerWebExchange exchange, WebFilterChain cha
5257 String cookieToken = cookieHelper .getCookieToken (exchange );
5358 return service .resolveSessionUserFromCookie (cookieToken )
5459 .switchIfEmpty (chain .filter (exchange ).then (Mono .empty ()))
55- .doOnNext (user -> {
60+ .map (user -> {
5661
57- List <String > tokensToRemove = new LinkedList <>();
62+ Connection activeConnection = null ;
63+ String orgId = null ;
5864
59- user .getConnections ().forEach (connection -> {
60- if (!connection .getAuthId ().equals (DEFAULT_AUTH_CONFIG .getId ())) {
61- Instant next5Minutes = Instant .now ().plusSeconds ( 300 );
62- if (connection .getAuthConnectionAuthToken ().getExpireAt () == 0 ) {
63- return ;
64- }
65- boolean isAccessTokenExpiryNear = (connection .getAuthConnectionAuthToken ().getExpireAt ()*1000 ) <= next5Minutes .toEpochMilli ();
66- if (isAccessTokenExpiryNear ) {
67- connection .getOrgIds ().forEach (orgId -> {
68- authenticationService .findAuthConfigByAuthId (orgId , connection .getAuthId ())
69- .doOnSuccess (findAuthConfig -> {
70- if (findAuthConfig == null ) {
71- return ;
72- }
73- OAuth2RequestContext oAuth2RequestContext = new OAuth2RequestContext (orgId , null , null );
74- oAuth2RequestContext .setAuthConfig (findAuthConfig .authConfig ());
75- AuthRequest authRequest = authRequestFactory .build (oAuth2RequestContext ).block ();
76- try {
77- AuthUser authUser = authRequest .refresh (connection .getAuthConnectionAuthToken ().getRefreshToken ()).block ();
78- authUser .setAuthContext (oAuth2RequestContext );
79- authenticationApiService .updateConnection (authUser , user );
80- } catch (Exception e ) {
81- log .error ("Failed to refresh access token. Removing user sessions/tokens." );
82- tokensToRemove .addAll (connection .getTokens ());
83- }
84- });
85- });
65+ Optional <Connection > activeConnectionOptional = user .getConnections ()
66+ .stream ()
67+ .filter (connection -> connection .getAuthId ().equals (user .getActiveAuthId ()))
68+ .findFirst ();
69+
70+ if (!activeConnectionOptional .isPresent ()) {
71+ return Triple .of (user , activeConnection , orgId );
72+ }
73+
74+ activeConnection = activeConnectionOptional .get ();
75+
76+ if (!activeConnection .getAuthId ().equals (DEFAULT_AUTH_CONFIG .getId ())) {
77+ if (activeConnection .getAuthConnectionAuthToken ().getExpireAt () == 0 ) {
78+ return Triple .of (user , activeConnection , orgId );
79+ }
80+ boolean isAccessTokenExpired = (activeConnection .getAuthConnectionAuthToken ().getExpireAt ()*1000 ) < Instant .now ().toEpochMilli ();
81+ if (isAccessTokenExpired ) {
82+
83+ Optional <String > orgIdOptional = activeConnection .getOrgIds ().stream ().findFirst ();
84+ if (!orgIdOptional .isPresent ()) {
85+ return Triple .of (user , activeConnection , orgId );
8686 }
87+ orgId = orgIdOptional .get ();
8788 }
88- });
89+ }
8990
90- tokensToRemove .forEach (token -> {
91- service .removeUserSession (token ).block ();
92- });
91+ return Triple .of (user , activeConnection , orgId );
9392
94- })
93+ }). flatMap ( this :: refreshOauthToken )
9594 .flatMap (user -> chain .filter (exchange ).contextWrite (withAuthentication (toAuthentication (user )))
9695 .then (service .extendValidity (cookieToken ))
9796 );
9897 }
98+
99+ private Mono <User > refreshOauthToken (Triple <User , Connection , String > triple ) {
100+
101+ User user = triple .getLeft ();
102+ Connection connection = triple .getMiddle ();
103+ String orgId = triple .getRight ();
104+
105+ if (connection == null || orgId == null ) {
106+ return Mono .just (user );
107+ }
108+
109+ OAuth2RequestContext oAuth2RequestContext = new OAuth2RequestContext (triple .getRight (), null , null );
110+
111+ return authenticationService
112+ .findAuthConfigByAuthId (orgId , connection .getAuthId ())
113+ .switchIfEmpty (Mono .empty ())
114+ .flatMap (findAuthConfig -> {
115+
116+ Mono <AuthRequest > authRequestMono = Mono .empty ();
117+
118+ if (findAuthConfig == null ) {
119+ return authRequestMono ;
120+ }
121+ oAuth2RequestContext .setAuthConfig (findAuthConfig .authConfig ());
122+
123+ return authRequestFactory .build (oAuth2RequestContext );
124+ }).flatMap (authRequest -> {
125+ if (authRequest == null ) {
126+ return Mono .just (user );
127+ }
128+ try {
129+ AuthUser authUser = authRequest .refresh (connection .getAuthConnectionAuthToken ().getRefreshToken ()).block ();
130+ authUser .setAuthContext (oAuth2RequestContext );
131+ authenticationApiService .updateConnection (authUser , user );
132+ return userService .update (user .getId (), user );
133+ } catch (Exception e ) {
134+ log .error ("Failed to refresh access token. Removing user sessions/tokens." );
135+ connection .getTokens ().forEach (token -> {
136+ service .removeUserSession (token ).block ();
137+ });
138+ }
139+ return Mono .just (user );
140+ });
141+
142+ }
143+
99144}
0 commit comments