(improvement)(auth) Support token key allocation based on the integration application. (#1119)

This commit is contained in:
lexluo09
2024-06-10 21:50:39 +08:00
committed by GitHub
parent 3f098a6364
commit 82a3e30472
9 changed files with 61 additions and 24 deletions

View File

@@ -6,6 +6,7 @@ import com.tencent.supersonic.auth.api.authentication.request.UserReq;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest;
/** /**
* UserAdaptor defines some interfaces for obtaining user and organization information * UserAdaptor defines some interfaces for obtaining user and organization information
@@ -20,7 +21,7 @@ public interface UserAdaptor {
void register(UserReq userReq); void register(UserReq userReq);
String login(UserReq userReq); String login(UserReq userReq, HttpServletRequest request);
List<User> getUserByOrg(String key); List<User> getUserByOrg(String key);

View File

@@ -1,6 +1,9 @@
package com.tencent.supersonic.auth.api.authentication.config; package com.tencent.supersonic.auth.api.authentication.config;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.Data; import lombok.Data;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -18,12 +21,18 @@ public class AuthenticationConfig {
@Value("${authentication.enable:false}") @Value("${authentication.enable:false}")
private boolean enabled; private boolean enabled;
@Value("${authentication.token.secret:secret}") @Value("${authentication.token.default.appKey:supersonic}")
private String tokenSecret; private String tokenDefaultAppKey;
@Value("${authentication.token.appSecret:supersonic:secret}")
private String tokenAppSecret;
@Value("${authentication.token.http.header.key:Authorization}") @Value("${authentication.token.http.header.key:Authorization}")
private String tokenHttpHeaderKey; private String tokenHttpHeaderKey;
@Value("${authentication.token.http.app.key:App-Key}")
private String tokenHttpHeaderAppKey;
@Value("${authentication.app.appId:appId}") @Value("${authentication.app.appId:appId}")
private String appId; private String appId;
@@ -35,4 +44,10 @@ public class AuthenticationConfig {
@Value("${authentication.token.timeout:7200000}") @Value("${authentication.token.timeout:7200000}")
private Long tokenTimeout; private Long tokenTimeout;
public Map<String, String> getAppKeyToSecretMap() {
return Arrays.stream(this.tokenAppSecret.split(","))
.map(s -> s.split(":"))
.collect(Collectors.toMap(e -> e[0].trim(), e -> e[1].trim()));
}
} }

View File

@@ -19,7 +19,7 @@ public interface UserService {
void register(UserReq userCmd); void register(UserReq userCmd);
String login(UserReq userCmd); String login(UserReq userCmd, HttpServletRequest request);
Set<String> getUserAllOrgId(String userName); Set<String> getUserAllOrgId(String userName);

View File

@@ -12,6 +12,7 @@ import com.tencent.supersonic.auth.authentication.persistence.repository.UserRep
import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil; import com.tencent.supersonic.auth.authentication.utils.AESEncryptionUtil;
import com.tencent.supersonic.auth.authentication.utils.UserTokenUtils; import com.tencent.supersonic.auth.authentication.utils.UserTokenUtils;
import com.tencent.supersonic.common.util.ContextUtils; import com.tencent.supersonic.common.util.ContextUtils;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import java.util.List; import java.util.List;
@@ -87,7 +88,7 @@ public class DefaultUserAdaptor implements UserAdaptor {
} }
@Override @Override
public String login(UserReq userReq) { public String login(UserReq userReq, HttpServletRequest request) {
UserTokenUtils userTokenUtils = ContextUtils.getBean(UserTokenUtils.class); UserTokenUtils userTokenUtils = ContextUtils.getBean(UserTokenUtils.class);
UserDO userDO = getUser(userReq.getName()); UserDO userDO = getUser(userReq.getName());
if (userDO == null) { if (userDO == null) {
@@ -100,7 +101,7 @@ public class DefaultUserAdaptor implements UserAdaptor {
if (userDO.getPassword().equals(password)) { if (userDO.getPassword().equals(password)) {
UserWithPassword user = UserWithPassword.get(userDO.getId(), userDO.getName(), userDO.getDisplayName(), UserWithPassword user = UserWithPassword.get(userDO.getId(), userDO.getName(), userDO.getDisplayName(),
userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin()); userDO.getEmail(), userDO.getPassword(), userDO.getIsAdmin());
return userTokenUtils.generateToken(user); return userTokenUtils.generateToken(user, request);
} else { } else {
throw new RuntimeException("password not correct, please try again"); throw new RuntimeException("password not correct, please try again");
} }

View File

@@ -66,7 +66,7 @@ public class DefaultAuthenticationInterceptor extends AuthenticationInterceptor
} }
private void setFakerUser(HttpServletRequest request) { private void setFakerUser(HttpServletRequest request) {
String token = userTokenUtils.generateAdminToken(); String token = userTokenUtils.generateAdminToken(request);
reflectSetparam(request, authenticationConfig.getTokenHttpHeaderKey(), token); reflectSetparam(request, authenticationConfig.getTokenHttpHeaderKey(), token);
setContext(User.getFakeUser().getName(), request); setContext(User.getFakeUser().getName(), request);
} }

View File

@@ -65,8 +65,8 @@ public class UserController {
} }
@PostMapping("/login") @PostMapping("/login")
public String login(@RequestBody UserReq userCmd) { public String login(@RequestBody UserReq userCmd, HttpServletRequest request) {
return userService.login(userCmd); return userService.login(userCmd, request);
} }
} }

View File

@@ -68,8 +68,8 @@ public class UserServiceImpl implements UserService {
} }
@Override @Override
public String login(UserReq userReq) { public String login(UserReq userReq, HttpServletRequest request) {
return ComponentFactory.getUserAdaptor().login(userReq); return ComponentFactory.getUserAdaptor().login(userReq, request);
} }
} }

View File

@@ -36,7 +36,7 @@ public class UserTokenUtils {
this.authenticationConfig = authenticationConfig; this.authenticationConfig = authenticationConfig;
} }
public String generateToken(UserWithPassword user) { public String generateToken(UserWithPassword user, HttpServletRequest request) {
Map<String, Object> claims = new HashMap<>(5); Map<String, Object> claims = new HashMap<>(5);
claims.put(TOKEN_USER_ID, user.getId()); claims.put(TOKEN_USER_ID, user.getId());
claims.put(TOKEN_USER_NAME, StringUtils.isEmpty(user.getName()) ? "" : user.getName()); claims.put(TOKEN_USER_NAME, StringUtils.isEmpty(user.getName()) ? "" : user.getName());
@@ -44,22 +44,23 @@ public class UserTokenUtils {
claims.put(TOKEN_USER_DISPLAY_NAME, user.getDisplayName()); claims.put(TOKEN_USER_DISPLAY_NAME, user.getDisplayName());
claims.put(TOKEN_CREATE_TIME, System.currentTimeMillis()); claims.put(TOKEN_CREATE_TIME, System.currentTimeMillis());
claims.put(TOKEN_IS_ADMIN, user.getIsAdmin()); claims.put(TOKEN_IS_ADMIN, user.getIsAdmin());
return generate(claims); String appKey = getAppKey(request);
return generate(claims, appKey);
} }
public String generateAdminToken() { public String generateAdminToken(HttpServletRequest request) {
UserWithPassword admin = new UserWithPassword("admin"); UserWithPassword admin = new UserWithPassword("admin");
admin.setId(1L); admin.setId(1L);
admin.setName("admin"); admin.setName("admin");
admin.setPassword("admin"); admin.setPassword("admin");
admin.setDisplayName("admin"); admin.setDisplayName("admin");
admin.setIsAdmin(1); admin.setIsAdmin(1);
return generateToken(admin); return generateToken(admin, request);
} }
public User getUser(HttpServletRequest request) { public User getUser(HttpServletRequest request) {
String token = request.getHeader(authenticationConfig.getTokenHttpHeaderKey()); String token = request.getHeader(authenticationConfig.getTokenHttpHeaderKey());
final Claims claims = getClaims(token); final Claims claims = getClaims(token, request);
Long userId = Long.parseLong(claims.getOrDefault(TOKEN_USER_ID, 0).toString()); Long userId = Long.parseLong(claims.getOrDefault(TOKEN_USER_ID, 0).toString());
String userName = String.valueOf(claims.get(TOKEN_USER_NAME)); String userName = String.valueOf(claims.get(TOKEN_USER_NAME));
String email = String.valueOf(claims.get(TOKEN_USER_EMAIL)); String email = String.valueOf(claims.get(TOKEN_USER_EMAIL));
@@ -76,7 +77,7 @@ public class UserTokenUtils {
log.warn("{}, uri: {}", message, request.getServletPath()); log.warn("{}, uri: {}", message, request.getServletPath());
throw new AccessException(message); throw new AccessException(message);
} }
final Claims claims = getClaims(token); final Claims claims = getClaims(token, request);
Long userId = Long.parseLong(claims.getOrDefault(TOKEN_USER_ID, 0).toString()); Long userId = Long.parseLong(claims.getOrDefault(TOKEN_USER_ID, 0).toString());
String userName = String.valueOf(claims.get(TOKEN_USER_NAME)); String userName = String.valueOf(claims.get(TOKEN_USER_NAME));
String email = String.valueOf(claims.get(TOKEN_USER_EMAIL)); String email = String.valueOf(claims.get(TOKEN_USER_EMAIL));
@@ -87,11 +88,13 @@ public class UserTokenUtils {
return UserWithPassword.get(userId, userName, displayName, email, password, isAdmin); return UserWithPassword.get(userId, userName, displayName, email, password, isAdmin);
} }
private Claims getClaims(String token) { private Claims getClaims(String token, HttpServletRequest request) {
Claims claims; Claims claims;
try { try {
String appKey = getAppKey(request);
String tokenSecret = getTokenSecret(appKey);
claims = Jwts.parser() claims = Jwts.parser()
.setSigningKey(authenticationConfig.getTokenSecret().getBytes(StandardCharsets.UTF_8)) .setSigningKey(tokenSecret.getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(token.startsWith(TOKEN_PREFIX) .parseClaimsJws(token.startsWith(TOKEN_PREFIX)
? token.substring(token.indexOf(TOKEN_PREFIX) + TOKEN_PREFIX.length()).trim() : ? token.substring(token.indexOf(TOKEN_PREFIX) + TOKEN_PREFIX.length()).trim() :
token.trim()).getBody(); token.trim()).getBody();
@@ -101,14 +104,15 @@ public class UserTokenUtils {
return claims; return claims;
} }
private String generate(Map<String, Object> claims) { private String generate(Map<String, Object> claims, String appKey) {
return toTokenString(claims); return toTokenString(claims, appKey);
} }
private String toTokenString(Map<String, Object> claims) { private String toTokenString(Map<String, Object> claims, String appKey) {
Long tokenTimeout = authenticationConfig.getTokenTimeout(); Long tokenTimeout = authenticationConfig.getTokenTimeout();
long expiration = Long.parseLong(claims.get(TOKEN_CREATE_TIME) + "") + tokenTimeout; long expiration = Long.parseLong(claims.get(TOKEN_CREATE_TIME) + "") + tokenTimeout;
Date expirationDate = new Date(expiration); Date expirationDate = new Date(expiration);
String tokenSecret = getTokenSecret(appKey);
SignatureAlgorithm.valueOf(TOKEN_ALGORITHM); SignatureAlgorithm.valueOf(TOKEN_ALGORITHM);
return Jwts.builder() return Jwts.builder()
@@ -116,8 +120,24 @@ public class UserTokenUtils {
.setSubject(claims.get(TOKEN_USER_NAME).toString()) .setSubject(claims.get(TOKEN_USER_NAME).toString())
.setExpiration(expirationDate) .setExpiration(expirationDate)
.signWith(SignatureAlgorithm.valueOf(TOKEN_ALGORITHM), .signWith(SignatureAlgorithm.valueOf(TOKEN_ALGORITHM),
authenticationConfig.getTokenSecret().getBytes(StandardCharsets.UTF_8)) tokenSecret.getBytes(StandardCharsets.UTF_8))
.compact(); .compact();
} }
private String getTokenSecret(String appKey) {
Map<String, String> appKeyToSecretMap = authenticationConfig.getAppKeyToSecretMap();
String secret = appKeyToSecretMap.get(appKey);
if (StringUtils.isBlank(secret)) {
throw new AccessException("get secret from appKey failed :" + appKey);
}
return secret;
}
private String getAppKey(HttpServletRequest request) {
String appKey = request.getHeader(authenticationConfig.getTokenHttpHeaderAppKey());
if (StringUtils.isBlank(appKey)) {
appKey = authenticationConfig.getTokenDefaultAppKey();
}
return appKey;
}
} }

View File

@@ -107,7 +107,7 @@ const LoginPage: React.FC = () => {
<Input <Input
size="large" size="large"
type="password" type="password"
placeholder="密码: admin123" placeholder="密码: 123456"
onPressEnter={handleLogin} onPressEnter={handleLogin}
prefix={<LockOutlined />} prefix={<LockOutlined />}
/> />