- pl.project13.maven
- git-commit-id-plugin
+ io.github.git-commit-id
+ git-commit-id-maven-plugin
${git.commit.plugin}
diff --git a/pig-common/pig-common-core/pom.xml b/pig-common/pig-common-core/pom.xml
index 7ce01119..4bb31f2a 100755
--- a/pig-common/pig-common-core/pom.xml
+++ b/pig-common/pig-common-core/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
pig-common-core
diff --git a/pig-common/pig-common-datasource/pom.xml b/pig-common/pig-common-datasource/pom.xml
index 0e2f5802..7bf9f85d 100644
--- a/pig-common/pig-common-datasource/pom.xml
+++ b/pig-common/pig-common-datasource/pom.xml
@@ -21,7 +21,7 @@
pig-common
com.pig4cloud
- 3.3.5
+ 3.4.0
4.0.0
diff --git a/pig-common/pig-common-feign/pom.xml b/pig-common/pig-common-feign/pom.xml
index f172916a..54446f1f 100755
--- a/pig-common/pig-common-feign/pom.xml
+++ b/pig-common/pig-common-feign/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
4.0.0
diff --git a/pig-common/pig-common-job/pom.xml b/pig-common/pig-common-job/pom.xml
index becfe697..9e4effd9 100755
--- a/pig-common/pig-common-job/pom.xml
+++ b/pig-common/pig-common-job/pom.xml
@@ -23,7 +23,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
pig-common-job
diff --git a/pig-common/pig-common-log/pom.xml b/pig-common/pig-common-log/pom.xml
index e5911ef7..a5808e86 100755
--- a/pig-common/pig-common-log/pom.xml
+++ b/pig-common/pig-common-log/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
pig-common-log
diff --git a/pig-common/pig-common-mybatis/pom.xml b/pig-common/pig-common-mybatis/pom.xml
index 97e06db0..13c68b12 100755
--- a/pig-common/pig-common-mybatis/pom.xml
+++ b/pig-common/pig-common-mybatis/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
pig-common-mybatis
diff --git a/pig-common/pig-common-security/pom.xml b/pig-common/pig-common-security/pom.xml
index 5e35fbed..cfa1d1a1 100755
--- a/pig-common/pig-common-security/pom.xml
+++ b/pig-common/pig-common-security/pom.xml
@@ -21,7 +21,7 @@
com.pig4cloud
pig-common
- 3.3.5
+ 3.4.0
pig-common-security
diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigLocalResourceServerTokenServices.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigLocalResourceServerTokenServices.java
new file mode 100644
index 00000000..ab48d2ff
--- /dev/null
+++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigLocalResourceServerTokenServices.java
@@ -0,0 +1,66 @@
+package com.pig4cloud.pig.common.security.component;
+
+import com.pig4cloud.pig.common.security.exception.UnauthorizedException;
+import com.pig4cloud.pig.common.security.service.PigUser;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.OAuth2Request;
+import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+/**
+ * @author lengleng
+ * @date 2020/9/29
+ */
+@RequiredArgsConstructor
+public class PigLocalResourceServerTokenServices implements ResourceServerTokenServices {
+
+ private final TokenStore tokenStore;
+
+ private final UserDetailsService userDetailsService;
+
+ @Override
+ public OAuth2Authentication loadAuthentication(String accessToken)
+ throws AuthenticationException, InvalidTokenException {
+ OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(accessToken);
+ if (oAuth2Authentication == null) {
+ return null;
+ }
+
+ OAuth2Request oAuth2Request = oAuth2Authentication.getOAuth2Request();
+ if (!(oAuth2Authentication.getPrincipal() instanceof PigUser)) {
+ return oAuth2Authentication;
+ }
+
+ // 根据 username 查询 spring cache 最新的值 并返回
+ PigUser pigxUser = (PigUser) oAuth2Authentication.getPrincipal();
+
+ UserDetails userDetails;
+ try {
+ userDetails = userDetailsService.loadUserByUsername(pigxUser.getUsername());
+ }
+ catch (UsernameNotFoundException notFoundException) {
+ throw new UnauthorizedException(String.format("%s username not found", pigxUser.getUsername()),
+ notFoundException);
+ }
+ Authentication userAuthentication = new UsernamePasswordAuthenticationToken(userDetails, "N/A",
+ userDetails.getAuthorities());
+ OAuth2Authentication authentication = new OAuth2Authentication(oAuth2Request, userAuthentication);
+ authentication.setAuthenticated(true);
+ return authentication;
+ }
+
+ @Override
+ public OAuth2AccessToken readAccessToken(String accessToken) {
+ throw new UnsupportedOperationException("Not supported: read access token");
+ }
+
+}
diff --git a/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigRedisTokenStore.java b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigRedisTokenStore.java
new file mode 100644
index 00000000..b0bfffd1
--- /dev/null
+++ b/pig-common/pig-common-security/src/main/java/com/pig4cloud/pig/common/security/component/PigRedisTokenStore.java
@@ -0,0 +1,478 @@
+package com.pig4cloud.pig.common.security.component;
+
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisZSetCommands;
+import org.springframework.data.redis.core.Cursor;
+import org.springframework.data.redis.core.ScanOptions;
+import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.common.OAuth2RefreshToken;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.token.AuthenticationKeyGenerator;
+import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy;
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
+import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStoreSerializationStrategy;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * @author efenderbosch
+ * @date 2020/9/30
+ *
+ * @link https://github.com/spring-projects/spring-security-oauth/pull/1660
+ * 重写RedisTokenStore ,主要解决 #1814 oauth2中client_id_to_access数据膨胀问题
+ */
+public class PigRedisTokenStore implements TokenStore {
+
+ private static final String ACCESS = "access:";
+
+ private static final String AUTH_TO_ACCESS = "auth_to_access:";
+
+ private static final String AUTH = "auth:";
+
+ private static final String REFRESH_AUTH = "refresh_auth:";
+
+ private static final String REFRESH = "refresh:";
+
+ private static final String REFRESH_TO_ACCESS = "refresh_to_access:";
+
+ private static final String CLIENT_ID_TO_ACCESS = "client_id_to_access_z:";
+
+ private static final String UNAME_TO_ACCESS = "uname_to_access_z:";
+
+ private static final boolean springDataRedis_2_0 = ClassUtils.isPresent(
+ "org.springframework.data.redis.connection.RedisStandaloneConfiguration",
+ RedisTokenStore.class.getClassLoader());
+
+ private final RedisConnectionFactory connectionFactory;
+
+ private AuthenticationKeyGenerator authenticationKeyGenerator = new DefaultAuthenticationKeyGenerator();
+
+ private RedisTokenStoreSerializationStrategy serializationStrategy = new JdkSerializationStrategy();
+
+ private String prefix = "";
+
+ private Method redisConnectionSet_2_0;
+
+ public PigRedisTokenStore(RedisConnectionFactory connectionFactory) {
+ this.connectionFactory = connectionFactory;
+ if (springDataRedis_2_0) {
+ this.loadRedisConnectionMethods_2_0();
+ }
+ }
+
+ public void setAuthenticationKeyGenerator(AuthenticationKeyGenerator authenticationKeyGenerator) {
+ this.authenticationKeyGenerator = authenticationKeyGenerator;
+ }
+
+ public void setSerializationStrategy(RedisTokenStoreSerializationStrategy serializationStrategy) {
+ this.serializationStrategy = serializationStrategy;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ private void loadRedisConnectionMethods_2_0() {
+ this.redisConnectionSet_2_0 = ReflectionUtils.findMethod(RedisConnection.class, "set", byte[].class,
+ byte[].class);
+ }
+
+ private RedisConnection getConnection() {
+ return connectionFactory.getConnection();
+ }
+
+ private byte[] serialize(Object object) {
+ return serializationStrategy.serialize(object);
+ }
+
+ private byte[] serializeKey(String object) {
+ return serialize(object);
+ }
+
+ private OAuth2AccessToken deserializeAccessToken(byte[] bytes) {
+ return serializationStrategy.deserialize(bytes, OAuth2AccessToken.class);
+ }
+
+ private OAuth2Authentication deserializeAuthentication(byte[] bytes) {
+ return serializationStrategy.deserialize(bytes, OAuth2Authentication.class);
+ }
+
+ private OAuth2RefreshToken deserializeRefreshToken(byte[] bytes) {
+ return serializationStrategy.deserialize(bytes, OAuth2RefreshToken.class);
+ }
+
+ private byte[] serialize(String string) {
+ return serializationStrategy.serialize(string);
+ }
+
+ private String deserializeString(byte[] bytes) {
+ return serializationStrategy.deserializeString(bytes);
+ }
+
+ @Override
+ public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
+ String key = authenticationKeyGenerator.extractKey(authentication);
+ byte[] serializedKey = serializeKey(AUTH_TO_ACCESS + key);
+ byte[] bytes;
+ try (RedisConnection conn = getConnection()) {
+ bytes = conn.get(serializedKey);
+ }
+ OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
+ if (accessToken != null) {
+ OAuth2Authentication storedAuthentication = readAuthentication(accessToken.getValue());
+ if ((storedAuthentication == null
+ || !key.equals(authenticationKeyGenerator.extractKey(storedAuthentication)))) {
+ // Keep the stores consistent (maybe the same user is
+ // represented by this authentication but the details have
+ // changed)
+ storeAccessToken(accessToken, authentication);
+ }
+
+ }
+ return accessToken;
+ }
+
+ @Override
+ public OAuth2Authentication readAuthentication(OAuth2AccessToken token) {
+ return readAuthentication(token.getValue());
+ }
+
+ @Override
+ public OAuth2Authentication readAuthentication(String token) {
+ byte[] bytes;
+ try (RedisConnection conn = getConnection()) {
+ bytes = conn.get(serializeKey(AUTH + token));
+ }
+ return deserializeAuthentication(bytes);
+ }
+
+ @Override
+ public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) {
+ return readAuthenticationForRefreshToken(token.getValue());
+ }
+
+ public OAuth2Authentication readAuthenticationForRefreshToken(String token) {
+ try (RedisConnection conn = getConnection()) {
+ byte[] bytes = conn.get(serializeKey(REFRESH_AUTH + token));
+ return deserializeAuthentication(bytes);
+ }
+ }
+
+ @Override
+ public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
+ byte[] serializedAccessToken = serialize(token);
+ byte[] serializedAuth = serialize(authentication);
+ byte[] accessKey = serializeKey(ACCESS + token.getValue());
+ byte[] authKey = serializeKey(AUTH + token.getValue());
+ byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + authenticationKeyGenerator.extractKey(authentication));
+ byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
+ byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
+
+ try (RedisConnection conn = getConnection()) {
+ conn.openPipeline();
+ if (springDataRedis_2_0) {
+ try {
+ this.redisConnectionSet_2_0.invoke(conn, accessKey, serializedAccessToken);
+ this.redisConnectionSet_2_0.invoke(conn, authKey, serializedAuth);
+ this.redisConnectionSet_2_0.invoke(conn, authToAccessKey, serializedAccessToken);
+ }
+ catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ else {
+ conn.set(accessKey, serializedAccessToken);
+ conn.set(authKey, serializedAuth);
+ conn.set(authToAccessKey, serializedAccessToken);
+ }
+
+ if (token.getExpiration() != null) {
+ int seconds = token.getExpiresIn();
+ long expirationTime = token.getExpiration().getTime();
+
+ if (!authentication.isClientOnly()) {
+ conn.zAdd(approvalKey, expirationTime, serializedAccessToken);
+ }
+ conn.zAdd(clientId, expirationTime, serializedAccessToken);
+
+ conn.expire(accessKey, seconds);
+ conn.expire(authKey, seconds);
+ conn.expire(authToAccessKey, seconds);
+ conn.expire(clientId, seconds);
+ conn.expire(approvalKey, seconds);
+ }
+ else {
+ conn.zAdd(clientId, -1, serializedAccessToken);
+ if (!authentication.isClientOnly()) {
+ conn.zAdd(approvalKey, -1, serializedAccessToken);
+ }
+ }
+ OAuth2RefreshToken refreshToken = token.getRefreshToken();
+ if (refreshToken != null && refreshToken.getValue() != null) {
+ byte[] auth = serialize(token.getValue());
+ byte[] refreshToAccessKey = serializeKey(REFRESH_TO_ACCESS + token.getRefreshToken().getValue());
+ if (springDataRedis_2_0) {
+ try {
+ this.redisConnectionSet_2_0.invoke(conn, refreshToAccessKey, auth);
+ }
+ catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ else {
+ conn.set(refreshToAccessKey, auth);
+ }
+ if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
+ ExpiringOAuth2RefreshToken expiringRefreshToken = (ExpiringOAuth2RefreshToken) refreshToken;
+ Date expiration = expiringRefreshToken.getExpiration();
+ if (expiration != null) {
+ int seconds = Long.valueOf((expiration.getTime() - System.currentTimeMillis()) / 1000L)
+ .intValue();
+ conn.expire(refreshToAccessKey, seconds);
+ }
+ }
+ }
+ conn.closePipeline();
+ }
+ }
+
+ private static String getApprovalKey(OAuth2Authentication authentication) {
+ String userName = authentication.getUserAuthentication() == null ? ""
+ : authentication.getUserAuthentication().getName();
+ return getApprovalKey(authentication.getOAuth2Request().getClientId(), userName);
+ }
+
+ private static String getApprovalKey(String clientId, String userName) {
+ return clientId + (userName == null ? "" : ":" + userName);
+ }
+
+ @Override
+ public void removeAccessToken(OAuth2AccessToken accessToken) {
+ removeAccessToken(accessToken.getValue());
+ }
+
+ @Override
+ public OAuth2AccessToken readAccessToken(String tokenValue) {
+ byte[] key = serializeKey(ACCESS + tokenValue);
+ byte[] bytes;
+ try (RedisConnection conn = getConnection()) {
+ bytes = conn.get(key);
+ }
+ return deserializeAccessToken(bytes);
+ }
+
+ public void removeAccessToken(String tokenValue) {
+ byte[] accessKey = serializeKey(ACCESS + tokenValue);
+ byte[] authKey = serializeKey(AUTH + tokenValue);
+ try (RedisConnection conn = getConnection()) {
+ conn.openPipeline();
+ conn.get(accessKey);
+ conn.get(authKey);
+ conn.del(accessKey);
+ // Don't remove the refresh token - it's up to the caller to do that
+ conn.del(authKey);
+ List