11
11
import jakarta .validation .constraints .NotEmpty ;
12
12
import lombok .RequiredArgsConstructor ;
13
13
import org .apache .commons .lang3 .StringUtils ;
14
+ import org .slf4j .Logger ;
15
+ import org .slf4j .LoggerFactory ;
14
16
import org .springframework .beans .factory .annotation .Value ;
15
17
import org .springframework .context .annotation .Configuration ;
16
18
29
31
import java .util .function .Consumer ;
30
32
import java .util .function .Supplier ;
31
33
34
+ /**
35
+ * According to the 'OAuth2AuthorizationService' implementation,
36
+ * When a single value is expected to be returned, there's no need to explicitly end the function name with "One".
37
+ * So when multiple values are expected to be returned, I have made the function name end with "List" to distinguish them.
38
+ * @author Andrew Kang
39
+ * @since 0.0.O
40
+ * @see OAuth2Authorization
41
+ * @see KnifeAuthorization
42
+ */
32
43
@ Configuration
33
44
@ RequiredArgsConstructor
34
45
public class OAuth2AuthorizationServiceImpl implements OAuth2AuthorizationService {
35
46
47
+ private static final Logger logger = LoggerFactory .getLogger (OAuth2AuthorizationServiceImpl .class );
48
+
36
49
private final KnifeAuthorizationRepository knifeAuthorizationRepository ;
37
50
private final SecurityPointCut securityPointCut ;
38
51
@@ -104,9 +117,6 @@ public void save(OAuth2Authorization shouldBeNewAuthorization) {
104
117
* 2. R for Read
105
118
* */
106
119
107
- /*
108
- * 1) AccessToken Token R + RefreshToken Token R
109
- * */
110
120
@ Override
111
121
public OAuth2Authorization findByToken (@ NotEmpty String tokenValue , @ Nullable OAuth2TokenType tokenType ) {
112
122
@@ -120,42 +130,12 @@ public OAuth2Authorization findByToken(@NotEmpty String tokenValue, @Nullable OA
120
130
return knifeAuthorizationRepository .findByStateOrAuthorizationCodeValueOrAccessTokenValueOrRefreshTokenValueOrOidcIdTokenValueOrUserCodeValueOrDeviceCodeValue (hashedTokenValue ).map (KnifeAuthorization ::getAttributes ).orElse (null );
121
131
}
122
132
}
123
- /*
124
- * 2) AccessToken Token R
125
- * */
126
- private @ Nullable OAuth2Authorization findOAuth2AuthorizationByAccessTokenValueSafely (Supplier <Optional <OAuth2Authorization >> authorizationSupplier , Consumer <Exception > exceptionHandler ) {
127
-
128
- OAuth2Authorization oAuth2Authorization = null ;
129
- try {
130
- oAuth2Authorization = authorizationSupplier .get ().orElse (null );
131
-
132
- } catch (Exception e ) {
133
-
134
- exceptionHandler .accept (e );
135
-
136
- // Retry only one more time
137
- oAuth2Authorization = authorizationSupplier .get ().orElse (null );
138
-
139
- }
140
-
141
- if (oAuth2Authorization != null && oAuth2Authorization .getAccessToken () != null
142
- && oAuth2Authorization .getAccessToken ().isExpired ()) {
143
- // 만료됨
144
- knifeAuthorizationRepository .deleteByAccessTokenValue (oAuth2Authorization .getAccessToken ().getToken ().getTokenValue ());
145
-
146
- return null ;
147
- }
148
- return oAuth2Authorization ;
149
- }
150
-
151
133
152
-
153
134
@ Override
154
135
public @ Nullable OAuth2Authorization findById (String id ) {
155
136
return knifeAuthorizationRepository .findById (id )
156
137
.map (KnifeAuthorization ::getAttributes )
157
138
.orElse (null );
158
-
159
139
}
160
140
161
141
@@ -165,22 +145,60 @@ public OAuth2Authorization findByToken(@NotEmpty String tokenValue, @Nullable OA
165
145
* [IMPORTANT] KEY = Username (principalName) + ClientId + AppToken
166
146
* Same ( org.springframework.security.core.userdetails : userName + spring-authorization-server : principalName )
167
147
* */
148
+ /**
149
+ * Returns the {@link OAuth2Authorization} identified by the provided {@code Username (principalName) + ClientId + AppToken}, or
150
+ * {@code null} if not found.
151
+ * @param userName org.springframework.security.core.userdetails, which is same as principalName
152
+ * @param clientId Oauth2 ROPC client_id
153
+ * @param appToken See the README
154
+ * @return the {@link OAuth2Authorization} if found, otherwise {@code null}
155
+ */
168
156
public @ Nullable OAuth2Authorization findByUserNameAndClientIdAndAppToken (@ NotEmpty String userName , @ NotEmpty String clientId , @ Nullable String appToken ) {
169
157
if (noAppTokenSameAccessToken ) {
170
- return findAuthorization (() -> knifeAuthorizationRepository .findValidAuthorizationByPrincipalNameAndClientIdAndNullableAppToken (userName , clientId , appToken ), userName , clientId , appToken );
158
+ return findSafelyByPrincipalNameAndClientIdAndAppToken (() -> knifeAuthorizationRepository .findValidAuthorizationByPrincipalNameAndClientIdAndNullableAppToken (userName , clientId , appToken ), userName , clientId , appToken );
171
159
} else {
172
- return findAuthorization (() -> knifeAuthorizationRepository .findValidAuthorizationByPrincipalNameAndClientIdAndAppToken (userName , clientId , appToken ), userName , clientId , appToken );
160
+ return findSafelyByPrincipalNameAndClientIdAndAppToken (() -> knifeAuthorizationRepository .findValidAuthorizationByPrincipalNameAndClientIdAndAppToken (userName , clientId , appToken ), userName , clientId , appToken );
173
161
}
174
162
}
175
163
176
- private @ Nullable OAuth2Authorization findAuthorization (Supplier <Optional <KnifeAuthorization >> authorizationSupplier , String userName , String clientId , @ Nullable String appToken ) {
177
- return findOAuth2AuthorizationByAccessTokenValueSafely (() -> authorizationSupplier .get ().map (KnifeAuthorization ::getAttributes ),
164
+ private @ Nullable OAuth2Authorization findSafelyByPrincipalNameAndClientIdAndAppToken (Supplier <Optional <KnifeAuthorization >> authorizationSupplier , String userName , String clientId , @ Nullable String appToken ) {
165
+ return findByAccessTokenValueSafely (() -> authorizationSupplier .get ().map (KnifeAuthorization ::getAttributes ),
178
166
e -> {
167
+
168
+ logger .warn ("Error finding authorization for user: {}, clientId: {}, appToken: {}" , userName , clientId , appToken , e );
169
+
170
+ // If multiple results are detected or other unexpected errors occur, remove access tokens for the account to prevent login errors.
179
171
knifeAuthorizationRepository .findListByPrincipalNameAndRegisteredClientIdAndAccessTokenAppToken (userName , clientId , appToken ).ifPresent (knifeAuthorizationRepository ::deleteAll );
180
172
knifeAuthorizationRepository .deleteByPrincipalNameAndRegisteredClientIdAndAccessTokenAppToken (userName , clientId , appToken );
181
173
});
182
174
}
183
175
176
+ private @ Nullable OAuth2Authorization findByAccessTokenValueSafely (Supplier <Optional <OAuth2Authorization >> authorizationSupplier , Consumer <Exception > exceptionHandler ) {
177
+
178
+ OAuth2Authorization oAuth2Authorization = null ;
179
+ try {
180
+ oAuth2Authorization = authorizationSupplier .get ().orElse (null );
181
+
182
+ } catch (Exception e ) {
183
+
184
+ exceptionHandler .accept (e );
185
+
186
+ // Retry only one more time
187
+ oAuth2Authorization = authorizationSupplier .get ().orElse (null );
188
+
189
+ }
190
+
191
+ if (oAuth2Authorization != null && oAuth2Authorization .getAccessToken () != null
192
+ && oAuth2Authorization .getAccessToken ().isExpired ()) {
193
+ // 만료됨
194
+ knifeAuthorizationRepository .deleteByAccessTokenValue (oAuth2Authorization .getAccessToken ().getToken ().getTokenValue ());
195
+
196
+ return null ;
197
+ }
198
+ return oAuth2Authorization ;
199
+ }
200
+
201
+
184
202
185
203
186
204
/*
0 commit comments