Skip to content

Commit d78b659

Browse files
committed
feature: add double token support for seata netty communication authentication
1 parent 679f86e commit d78b659

File tree

33 files changed

+1093
-377
lines changed

33 files changed

+1093
-377
lines changed

common/src/main/java/org/apache/seata/common/ConfigurationKeys.java

+30
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ public interface ConfigurationKeys {
6868
*/
6969
String SEATA_PREFIX = SEATA_FILE_ROOT_CONFIG + ".";
7070

71+
/**
72+
* The constant SECURITY_PREFIX
73+
*/
74+
String SECURITY_PREFIX = "security.";
75+
7176
/**
7277
* The constant SERVICE_PREFIX.
7378
*/
@@ -1014,6 +1019,31 @@ public interface ConfigurationKeys {
10141019
*/
10151020
String SERVER_APPLICATION_DATA_SIZE_CHECK = SERVER_PREFIX + "applicationDataLimitCheck";
10161021

1022+
/**
1023+
* The constant SECURITY_USERNAME;
1024+
*/
1025+
String SECURITY_USERNME = SECURITY_PREFIX + "username";
1026+
1027+
/**
1028+
* The constant SECURITY_PASSWORD;
1029+
*/
1030+
String SECURITY_PASSWORD = SECURITY_PREFIX + "password";
1031+
1032+
/**
1033+
* The constant SECURITY_SECRET_KEY;
1034+
*/
1035+
String SECURITY_SECRET_KEY = SECURITY_PREFIX + "secretKey";
1036+
1037+
/**
1038+
* The constant SECURITY_ACCESS_TOKEN_VALID_TIME;
1039+
*/
1040+
String SECURITY_ACCESS_TOKEN_VALID_TIME = SECURITY_PREFIX + "accessTokenValidityInMilliseconds";
1041+
1042+
/**
1043+
* The constant SECURITY_REFRESH_TOKEN_VALID_TIME;
1044+
*/
1045+
String SECURITY_REFRESH_TOKEN_VALID_TIME = SECURITY_PREFIX + "refreshTokenValidityInMilliseconds";
1046+
10171047
/**
10181048
* The constant ROCKET_MQ_MSG_TIMEOUT
10191049
*/

common/src/main/java/org/apache/seata/common/util/StringUtils.java

+40-9
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,24 @@
1616
*/
1717
package org.apache.seata.common.util;
1818

19+
import org.apache.seata.common.Constants;
20+
import org.apache.seata.common.exception.ShouldNeverHappenException;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
1924
import java.io.ByteArrayOutputStream;
2025
import java.io.InputStream;
2126
import java.lang.annotation.Annotation;
2227
import java.lang.reflect.Field;
2328
import java.lang.reflect.Method;
2429
import java.nio.charset.StandardCharsets;
2530
import java.text.SimpleDateFormat;
26-
import java.util.Collection;
27-
import java.util.Date;
28-
import java.util.Iterator;
29-
import java.util.Map;
31+
import java.util.*;
3032
import java.util.regex.Matcher;
3133
import java.util.regex.Pattern;
3234

33-
import org.apache.seata.common.Constants;
34-
import org.apache.seata.common.exception.ShouldNeverHappenException;
35-
import org.slf4j.Logger;
36-
import org.slf4j.LoggerFactory;
35+
import static org.apache.seata.common.ConfigurationKeys.EXTRA_DATA_KV_CHAR;
36+
import static org.apache.seata.common.ConfigurationKeys.EXTRA_DATA_SPLIT_CHAR;
3737

3838
/**
3939
* The type String utils.
@@ -331,7 +331,7 @@ public static boolean isNotEmpty(final CharSequence cs) {
331331

332332
/**
333333
* hump to Line or line to hump, only spring environment use
334-
*
334+
*
335335
* @param str str
336336
* @return string string
337337
*/
@@ -446,4 +446,35 @@ public static boolean hasText(CharSequence str) {
446446
return false;
447447
}
448448

449+
public static HashMap<String, String> string2Map(String inputString) {
450+
HashMap<String, String> resultMap = new HashMap<>();
451+
if (StringUtils.isBlank(inputString)) {
452+
return resultMap;
453+
}
454+
String[] keyValuePairs = inputString.split(EXTRA_DATA_SPLIT_CHAR);
455+
for (String pair : keyValuePairs) {
456+
String[] keyValue = pair.trim().split(EXTRA_DATA_KV_CHAR);
457+
if (keyValue.length == 2) {
458+
resultMap.put(keyValue[0].trim(), keyValue[1].trim());
459+
}
460+
}
461+
return resultMap;
462+
}
463+
464+
public static String map2String(HashMap<String, String> inputMap) {
465+
if (inputMap == null || inputMap.isEmpty()) {
466+
return "";
467+
}
468+
StringBuilder resultString = new StringBuilder();
469+
for (Map.Entry<String, String> entry : inputMap.entrySet()) {
470+
String key = entry.getKey();
471+
String value = entry.getValue();
472+
String pair = key + EXTRA_DATA_KV_CHAR + value + EXTRA_DATA_SPLIT_CHAR;
473+
resultString.append(pair);
474+
}
475+
if (resultString.length() > 0) {
476+
resultString.deleteCharAt(resultString.length() - 1);
477+
}
478+
return resultString.toString();
479+
}
449480
}

console/src/main/java/org/apache/seata/console/controller/AuthController.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
*/
1717
package org.apache.seata.console.controller;
1818

19-
import javax.servlet.http.HttpServletResponse;
20-
2119
import org.apache.seata.common.result.Code;
22-
import org.apache.seata.console.config.WebSecurityConfig;
2320
import org.apache.seata.common.result.SingleResult;
21+
import org.apache.seata.console.config.WebSecurityConfig;
2422
import org.apache.seata.console.security.User;
2523
import org.apache.seata.console.utils.JwtTokenUtils;
2624
import org.springframework.beans.factory.annotation.Autowired;
@@ -34,6 +32,8 @@
3432
import org.springframework.web.bind.annotation.RequestMapping;
3533
import org.springframework.web.bind.annotation.RestController;
3634

35+
import javax.servlet.http.HttpServletResponse;
36+
3737
/**
3838
* auth user
3939
*
@@ -58,7 +58,6 @@ public class AuthController {
5858
public SingleResult<String> login(HttpServletResponse response, @RequestBody User user) {
5959
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
6060
user.getUsername(), user.getPassword());
61-
6261
try {
6362
//AuthenticationManager(default ProviderManager) #authenticate check Authentication
6463
Authentication authentication = authenticationManager.authenticate(authenticationToken);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.apache.seata.core.auth;
2+
3+
import org.apache.seata.core.protocol.ResultCode;
4+
5+
public class AuthResult {
6+
private ResultCode resultCode;
7+
8+
private String accessToken;
9+
10+
private String refreshToken;
11+
12+
public AuthResult() {
13+
}
14+
15+
public AuthResult(AuthResultBuilder builder) {
16+
this.resultCode = builder.getResultCode();
17+
this.accessToken = builder.getAccessToken();
18+
this.refreshToken = builder.getRefreshToken();
19+
}
20+
21+
public ResultCode getResultCode() {
22+
return resultCode;
23+
}
24+
25+
public void setResultCode(ResultCode resultCode) {
26+
this.resultCode = resultCode;
27+
}
28+
29+
public String getAccessToken() {
30+
return accessToken;
31+
}
32+
33+
public void setAccessToken(String accessToken) {
34+
this.accessToken = accessToken;
35+
}
36+
37+
public String getRefreshToken() {
38+
return refreshToken;
39+
}
40+
41+
public void setRefreshToken(String refreshToken) {
42+
this.refreshToken = refreshToken;
43+
}
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package org.apache.seata.core.auth;
2+
3+
import org.apache.seata.core.protocol.ResultCode;
4+
5+
public class AuthResultBuilder {
6+
private ResultCode resultCode;
7+
private String accessToken;
8+
private String refreshToken;
9+
10+
public ResultCode getResultCode() {
11+
return resultCode;
12+
}
13+
14+
public String getAccessToken() {
15+
return accessToken;
16+
}
17+
18+
public String getRefreshToken() {
19+
return refreshToken;
20+
}
21+
22+
// 设置 resultCode
23+
public AuthResultBuilder setResultCode(ResultCode resultCode) {
24+
this.resultCode = resultCode;
25+
return this;
26+
}
27+
28+
// 设置 accessToken
29+
public AuthResultBuilder setAccessToken(String accessToken) {
30+
this.accessToken = accessToken;
31+
return this;
32+
}
33+
34+
// 设置 refreshToken
35+
public AuthResultBuilder setRefreshToken(String refreshToken) {
36+
this.refreshToken = refreshToken;
37+
return this;
38+
}
39+
40+
// 构建最终的 AuthResult 对象
41+
public AuthResult build() {
42+
return new AuthResult(this);
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.seata.core.auth;
18+
19+
20+
import org.apache.seata.common.ConfigurationKeys;
21+
import org.apache.seata.common.util.StringUtils;
22+
import org.apache.seata.config.ConfigurationFactory;
23+
24+
import java.util.HashMap;
25+
26+
public class JwtAuthManager {
27+
private String refreshToken;
28+
29+
private String accessToken;
30+
31+
private boolean isAccessTokenNearExpiration;
32+
33+
private String username;
34+
35+
private String password;
36+
37+
public final static String PRO_USERNAME = "username";
38+
39+
public final static String PRO_PASSWORD = "password";
40+
41+
public final static String PRO_TOKEN = "token";
42+
43+
public final static String PRO_REFRESH_TOKEN = "refresh_token";
44+
45+
private static volatile JwtAuthManager instance;
46+
47+
private JwtAuthManager() {
48+
}
49+
50+
public static JwtAuthManager getInstance() {
51+
if (instance == null) {
52+
synchronized (JwtAuthManager.class) {
53+
if (instance == null) {
54+
instance = new JwtAuthManager();
55+
instance.username = ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig(ConfigurationKeys.SECURITY_USERNME);
56+
instance.password = ConfigurationFactory.CURRENT_FILE_INSTANCE.getConfig(ConfigurationKeys.SECURITY_PASSWORD);
57+
instance.isAccessTokenNearExpiration = false;
58+
}
59+
}
60+
}
61+
return instance;
62+
}
63+
64+
public void init() {
65+
}
66+
67+
public boolean isAccessTokenNearExpiration() {
68+
return isAccessTokenNearExpiration;
69+
}
70+
71+
public void setAccessTokenNearExpiration(boolean accessTokenNearExpiration) {
72+
isAccessTokenNearExpiration = accessTokenNearExpiration;
73+
}
74+
75+
public String getAccessToken() {
76+
return accessToken;
77+
}
78+
79+
public String getRefreshToken() {
80+
return refreshToken;
81+
}
82+
83+
public String getUsername() {
84+
return username;
85+
}
86+
87+
public void setUsername(String username) {
88+
this.username = username;
89+
}
90+
91+
public String getPassword() {
92+
return password;
93+
}
94+
95+
public void setPassword(String password) {
96+
this.password = password;
97+
}
98+
99+
public void refreshToken(String newAccessToken, String newRefreshToken) {
100+
if (newAccessToken != null) {
101+
accessToken = newAccessToken;
102+
isAccessTokenNearExpiration = false;
103+
}
104+
if (newRefreshToken != null) {
105+
refreshToken = newRefreshToken;
106+
}
107+
}
108+
109+
public void setAccessToken(String token) {
110+
accessToken = token;
111+
}
112+
113+
public void setRefreshToken(String token) {
114+
refreshToken = token;
115+
}
116+
117+
public String getAuthData() {
118+
HashMap<String, String> extraDataMap = new HashMap<>();
119+
extraDataMap.remove(PRO_TOKEN);
120+
if (accessToken != null && !isAccessTokenNearExpiration) {
121+
extraDataMap.put(PRO_TOKEN, accessToken);
122+
} else if (refreshToken != null) {
123+
extraDataMap.put(PRO_REFRESH_TOKEN, refreshToken);
124+
} else if (username != null && password != null) {
125+
extraDataMap.put(PRO_USERNAME, username);
126+
extraDataMap.put(PRO_PASSWORD, password);
127+
}
128+
return StringUtils.map2String(extraDataMap);
129+
}
130+
131+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.apache.seata.core.auth;
2+
3+
import io.netty.channel.Channel;
4+
import org.apache.seata.core.protocol.RegisterRMResponse;
5+
6+
public interface RegisterHandler {
7+
/**
8+
* On a register response received.
9+
*
10+
* @param response received response message
11+
* @param channel channel of the response
12+
*/
13+
void onRegisterResponse(RegisterRMResponse response, Channel channel, Integer rpcId);
14+
}

0 commit comments

Comments
 (0)