mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-22 12:48:58 +08:00
🔖 Releasing / Version tags. 3.4.0
🔖 Releasing / Version tags. 3.4.0
This commit is contained in:
parent
14eb346f1c
commit
3ce61d2f7a
@ -7,5 +7,4 @@
|
|||||||
### 回显步骤
|
### 回显步骤
|
||||||
|
|
||||||
|
|
||||||
|
### 报错信息 、截图 截图 !!!
|
||||||
### 报错信息
|
|
||||||
|
9
.github/workflows/maven.yml
vendored
9
.github/workflows/maven.yml
vendored
@ -55,12 +55,3 @@ jobs:
|
|||||||
# 💤🤷♀️ failure 🙅♂️💣 [pig-mesh/pig](https://github.com/pig-mesh/pig)
|
# 💤🤷♀️ failure 🙅♂️💣 [pig-mesh/pig](https://github.com/pig-mesh/pig)
|
||||||
> Github Action: https://github.com/pig-mesh/pig failure
|
> Github Action: https://github.com/pig-mesh/pig failure
|
||||||
> (⋟﹏⋞) from github action message
|
> (⋟﹏⋞) from github action message
|
||||||
- uses: shaowenchen/debugger-action@v2
|
|
||||||
if: github.repository == 'pig-mesh/pig'
|
|
||||||
name: debugger
|
|
||||||
continue-on-error: true
|
|
||||||
with:
|
|
||||||
frp_server_addr: ${{ secrets.FRP_SERVER_ADDR }}
|
|
||||||
frp_server_port: ${{ secrets.FRP_SERVER_PORT }}
|
|
||||||
frp_token: ${{ secrets.FRP_TOKEN }}
|
|
||||||
ssh_port: ${{ secrets.SSH_PORT }}
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -34,6 +34,7 @@ target/
|
|||||||
*.zip
|
*.zip
|
||||||
*.tar
|
*.tar
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
|
*.versionsBackup
|
||||||
|
|
||||||
### vscode ###
|
### vscode ###
|
||||||
.vscode
|
.vscode
|
||||||
|
32
README.md
32
README.md
@ -13,6 +13,20 @@
|
|||||||
- 提供对常见容器化支持 Docker、Kubernetes、Rancher2 支持
|
- 提供对常见容器化支持 Docker、Kubernetes、Rancher2 支持
|
||||||
- 提供 lambda 、stream api 、webflux 的生产实践
|
- 提供 lambda 、stream api 、webflux 的生产实践
|
||||||
|
|
||||||
|
## 文档视频
|
||||||
|
|
||||||
|
[文档视频 wiki.pig4cloud.com](https://wiki.pig4cloud.com)
|
||||||
|
|
||||||
|
[PIGX 在线体验 pigx.pig4cloud.com](http://pigx.pig4cloud.com)
|
||||||
|
|
||||||
|
[产品白皮书 paper.pig4cloud.com](https://paper.pig4cloud.com)
|
||||||
|
|
||||||
|
## 微信群 [禁广告]
|
||||||
|
|
||||||
|
![1628762721](https://minio.pigx.vip/oss/1628762721.png)
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
### 核心依赖
|
### 核心依赖
|
||||||
|
|
||||||
| 依赖 | 版本 |
|
| 依赖 | 版本 |
|
||||||
@ -22,7 +36,7 @@
|
|||||||
| Spring Cloud Alibaba | 2021.1 |
|
| Spring Cloud Alibaba | 2021.1 |
|
||||||
| Spring Security OAuth2 | 2.3.6 |
|
| Spring Security OAuth2 | 2.3.6 |
|
||||||
| Mybatis Plus | 3.4.3.5 |
|
| Mybatis Plus | 3.4.3.5 |
|
||||||
| hutool | 5.7.13 |
|
| hutool | 5.7.14 |
|
||||||
| Avue | 2.6.18 |
|
| Avue | 2.6.18 |
|
||||||
|
|
||||||
### 模块说明
|
### 模块说明
|
||||||
@ -55,16 +69,6 @@ pig
|
|||||||
└── pig-xxl-job-admin -- 分布式定时任务管理台 [5004]
|
└── pig-xxl-job-admin -- 分布式定时任务管理台 [5004]
|
||||||
```
|
```
|
||||||
|
|
||||||
## 文档视频
|
|
||||||
|
|
||||||
[文档视频 wiki.pig4cloud.com](https://wiki.pig4cloud.com)
|
|
||||||
|
|
||||||
[PIGX 在线体验 pigx.pig4cloud.com](http://pigx.pig4cloud.com)
|
|
||||||
|
|
||||||
[产品白皮书 paper.pig4cloud.com](https://paper.pig4cloud.com)
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 本地开发 运行
|
### 本地开发 运行
|
||||||
|
|
||||||
pig 提供了详细的[部署文档 wiki.pig4cloud.com](https://www.yuque.com/pig4cloud/pig/vsdox9),包括开发环境安装、服务端代码运行、前端代码运行等。
|
pig 提供了详细的[部署文档 wiki.pig4cloud.com](https://www.yuque.com/pig4cloud/pig/vsdox9),包括开发环境安装、服务端代码运行、前端代码运行等。
|
||||||
@ -74,6 +78,7 @@ pig 提供了详细的[部署文档 wiki.pig4cloud.com](https://www.yuque.com/pi
|
|||||||
### 定制自己微服务
|
### 定制自己微服务
|
||||||
|
|
||||||
[PIG DIY](https://diy.pig4cloud.com)
|
[PIG DIY](https://diy.pig4cloud.com)
|
||||||
|
|
||||||
[PIG ARCHETYPE](https://archetype.pig4cloud.com)
|
[PIG ARCHETYPE](https://archetype.pig4cloud.com)
|
||||||
|
|
||||||
### Docker 运行
|
### Docker 运行
|
||||||
@ -105,11 +110,6 @@ npm run build:docker && docker-compose up -d
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## 微信群 [禁广告]
|
|
||||||
|
|
||||||
![1628762721](https://minio.pigx.vip/oss/1628762721.png)
|
|
||||||
|
|
||||||
|
|
||||||
## 开源共建
|
## 开源共建
|
||||||
|
|
||||||
### 开源协议
|
### 开源协议
|
||||||
|
@ -12,7 +12,7 @@ services:
|
|||||||
- 3306:3306
|
- 3306:3306
|
||||||
|
|
||||||
pig-redis:
|
pig-redis:
|
||||||
image: redis:6.0
|
image: redis:6.2.6
|
||||||
ports:
|
ports:
|
||||||
- 6379:6379
|
- 6379:6379
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-auth</artifactId>
|
<artifactId>pig-auth</artifactId>
|
||||||
|
@ -16,19 +16,19 @@
|
|||||||
|
|
||||||
package com.pig4cloud.pig.auth.config;
|
package com.pig4cloud.pig.auth.config;
|
||||||
|
|
||||||
import com.pig4cloud.pig.common.core.constant.CacheConstants;
|
|
||||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
||||||
import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator;
|
import com.pig4cloud.pig.common.security.component.PigWebResponseExceptionTranslator;
|
||||||
import com.pig4cloud.pig.common.security.grant.ResourceOwnerCustomeAppTokenGranter;
|
import com.pig4cloud.pig.common.security.grant.ResourceOwnerCustomeAppTokenGranter;
|
||||||
import com.pig4cloud.pig.common.security.service.PigClientDetailsService;
|
import com.pig4cloud.pig.common.security.service.PigClientDetailsService;
|
||||||
import com.pig4cloud.pig.common.security.service.PigUser;
|
import com.pig4cloud.pig.common.security.service.PigCustomTokenServices;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authentication.ProviderManager;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
|
||||||
@ -36,17 +36,15 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.A
|
|||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
|
||||||
|
import org.springframework.security.oauth2.provider.ClientDetailsService;
|
||||||
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
|
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
|
||||||
import org.springframework.security.oauth2.provider.TokenGranter;
|
import org.springframework.security.oauth2.provider.TokenGranter;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||||
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
@ -63,7 +61,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
|
|
||||||
private final AuthenticationManager authenticationManager;
|
private final AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
private final RedisConnectionFactory redisConnectionFactory;
|
private final TokenStore redisTokenStore;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@ -78,8 +76,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
||||||
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenStore(tokenStore())
|
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenServices(tokenServices())
|
||||||
.tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService)
|
.tokenStore(redisTokenStore).tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService)
|
||||||
.authenticationManager(authenticationManager).reuseRefreshTokens(false)
|
.authenticationManager(authenticationManager).reuseRefreshTokens(false)
|
||||||
.pathMapping("/oauth/confirm_access", "/token/confirm_access")
|
.pathMapping("/oauth/confirm_access", "/token/confirm_access")
|
||||||
.exceptionTranslator(new PigWebResponseExceptionTranslator());
|
.exceptionTranslator(new PigWebResponseExceptionTranslator());
|
||||||
@ -98,33 +96,42 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
|||||||
endpoints.tokenGranter(compositeTokenGranter);
|
endpoints.tokenGranter(compositeTokenGranter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public TokenStore tokenStore() {
|
|
||||||
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
|
|
||||||
tokenStore.setPrefix(CacheConstants.PROJECT_OAUTH_ACCESS);
|
|
||||||
return tokenStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public TokenEnhancer tokenEnhancer() {
|
public TokenEnhancer tokenEnhancer() {
|
||||||
return (accessToken, authentication) -> {
|
return (accessToken, authentication) -> {
|
||||||
final Map<String, Object> additionalInfo = new HashMap<>(4);
|
final Map<String, Object> additionalInfo = new HashMap<>(4);
|
||||||
PigUser pigUser = (PigUser) authentication.getUserAuthentication().getPrincipal();
|
|
||||||
additionalInfo.put(SecurityConstants.DETAILS_LICENSE, SecurityConstants.PROJECT_LICENSE);
|
additionalInfo.put(SecurityConstants.DETAILS_LICENSE, SecurityConstants.PROJECT_LICENSE);
|
||||||
additionalInfo.put(SecurityConstants.DETAILS_USER_ID, pigUser.getId());
|
|
||||||
additionalInfo.put(SecurityConstants.DETAILS_USERNAME, pigUser.getUsername());
|
|
||||||
additionalInfo.put(SecurityConstants.DETAILS_DEPT_ID, pigUser.getDeptId());
|
|
||||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
|
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
|
||||||
return accessToken;
|
return accessToken;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PigClientDetailsService pigClientDetailsService() {
|
public ClientDetailsService pigClientDetailsService() {
|
||||||
PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource);
|
PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource);
|
||||||
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
|
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
|
||||||
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
|
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
|
||||||
return clientDetailsService;
|
return clientDetailsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PigCustomTokenServices tokenServices() {
|
||||||
|
PigCustomTokenServices tokenServices = new PigCustomTokenServices();
|
||||||
|
tokenServices.setTokenStore(redisTokenStore);
|
||||||
|
tokenServices.setSupportRefreshToken(true);
|
||||||
|
tokenServices.setReuseRefreshToken(false);
|
||||||
|
tokenServices.setClientDetailsService(pigClientDetailsService());
|
||||||
|
tokenServices.setTokenEnhancer(tokenEnhancer());
|
||||||
|
addUserDetailsService(tokenServices, userDetailsService);
|
||||||
|
return tokenServices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addUserDetailsService(PigCustomTokenServices tokenServices, UserDetailsService userDetailsService) {
|
||||||
|
if (userDetailsService != null) {
|
||||||
|
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
|
||||||
|
provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsService));
|
||||||
|
tokenServices.setAuthenticationManager(new ProviderManager(Collections.singletonList(provider)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common-bom</artifactId>
|
<artifactId>pig-common-bom</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>pig-common-bom</name>
|
<name>pig-common-bom</name>
|
||||||
@ -20,9 +20,9 @@
|
|||||||
<security.oauth.version>2.1.8.RELEASE</security.oauth.version>
|
<security.oauth.version>2.1.8.RELEASE</security.oauth.version>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
<git.commit.plugin>2.2.5</git.commit.plugin>
|
<git.commit.plugin>5.0.0</git.commit.plugin>
|
||||||
<spring.checkstyle.plugin>0.0.28</spring.checkstyle.plugin>
|
<spring.checkstyle.plugin>0.0.29</spring.checkstyle.plugin>
|
||||||
<fastjson.version>1.2.75</fastjson.version>
|
<fastjson.version>1.2.78</fastjson.version>
|
||||||
<swagger.core.version>1.5.24</swagger.core.version>
|
<swagger.core.version>1.5.24</swagger.core.version>
|
||||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||||
<nacos.version>2.0.3</nacos.version>
|
<nacos.version>2.0.3</nacos.version>
|
||||||
@ -150,8 +150,8 @@
|
|||||||
<plugins>
|
<plugins>
|
||||||
<!--打包jar 与git commit 关联插件-->
|
<!--打包jar 与git commit 关联插件-->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>pl.project13.maven</groupId>
|
<groupId>io.github.git-commit-id</groupId>
|
||||||
<artifactId>git-commit-id-plugin</artifactId>
|
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||||
<version>${git.commit.plugin}</version>
|
<version>${git.commit.plugin}</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!--代码格式插件,默认使用spring 规则-->
|
<!--代码格式插件,默认使用spring 规则-->
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-core</artifactId>
|
<artifactId>pig-common-core</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-job</artifactId>
|
<artifactId>pig-common-job</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-log</artifactId>
|
<artifactId>pig-common-log</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-mybatis</artifactId>
|
<artifactId>pig-common-mybatis</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-security</artifactId>
|
<artifactId>pig-common-security</artifactId>
|
||||||
|
@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
* <p>
|
||||||
|
* @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<Object> results = conn.closePipeline();
|
||||||
|
byte[] access = (byte[]) results.get(0);
|
||||||
|
byte[] auth = (byte[]) results.get(1);
|
||||||
|
|
||||||
|
OAuth2Authentication authentication = deserializeAuthentication(auth);
|
||||||
|
if (authentication != null) {
|
||||||
|
String key = authenticationKeyGenerator.extractKey(authentication);
|
||||||
|
byte[] authToAccessKey = serializeKey(AUTH_TO_ACCESS + key);
|
||||||
|
byte[] unameKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(authentication));
|
||||||
|
byte[] clientId = serializeKey(CLIENT_ID_TO_ACCESS + authentication.getOAuth2Request().getClientId());
|
||||||
|
conn.openPipeline();
|
||||||
|
conn.del(authToAccessKey);
|
||||||
|
conn.zRem(unameKey, access);
|
||||||
|
conn.zRem(clientId, access);
|
||||||
|
conn.del(serialize(ACCESS + key));
|
||||||
|
conn.closePipeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
|
||||||
|
byte[] refreshKey = serializeKey(REFRESH + refreshToken.getValue());
|
||||||
|
byte[] refreshAuthKey = serializeKey(REFRESH_AUTH + refreshToken.getValue());
|
||||||
|
byte[] serializedRefreshToken = serialize(refreshToken);
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
conn.openPipeline();
|
||||||
|
if (springDataRedis_2_0) {
|
||||||
|
try {
|
||||||
|
this.redisConnectionSet_2_0.invoke(conn, refreshKey, serializedRefreshToken);
|
||||||
|
this.redisConnectionSet_2_0.invoke(conn, refreshAuthKey, serialize(authentication));
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conn.set(refreshKey, serializedRefreshToken);
|
||||||
|
conn.set(refreshAuthKey, serialize(authentication));
|
||||||
|
}
|
||||||
|
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(refreshKey, seconds);
|
||||||
|
conn.expire(refreshAuthKey, seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.closePipeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2RefreshToken readRefreshToken(String tokenValue) {
|
||||||
|
byte[] key = serializeKey(REFRESH + tokenValue);
|
||||||
|
byte[] bytes;
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
bytes = conn.get(key);
|
||||||
|
}
|
||||||
|
return deserializeRefreshToken(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||||
|
removeRefreshToken(refreshToken.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRefreshToken(String tokenValue) {
|
||||||
|
byte[] refreshKey = serializeKey(REFRESH + tokenValue);
|
||||||
|
byte[] refreshAuthKey = serializeKey(REFRESH_AUTH + tokenValue);
|
||||||
|
byte[] refresh2AccessKey = serializeKey(REFRESH_TO_ACCESS + tokenValue);
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
conn.openPipeline();
|
||||||
|
conn.del(refreshKey);
|
||||||
|
conn.del(refreshAuthKey);
|
||||||
|
conn.del(refresh2AccessKey);
|
||||||
|
conn.closePipeline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) {
|
||||||
|
removeAccessTokenUsingRefreshToken(refreshToken.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeAccessTokenUsingRefreshToken(String refreshToken) {
|
||||||
|
byte[] key = serializeKey(REFRESH_TO_ACCESS + refreshToken);
|
||||||
|
List<Object> results;
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
conn.openPipeline();
|
||||||
|
conn.get(key);
|
||||||
|
conn.del(key);
|
||||||
|
results = conn.closePipeline();
|
||||||
|
}
|
||||||
|
byte[] bytes = (byte[]) results.get(0);
|
||||||
|
String accessToken = deserializeString(bytes);
|
||||||
|
if (accessToken != null) {
|
||||||
|
removeAccessToken(accessToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<byte[]> getZByteLists(byte[] key, RedisConnection conn) {
|
||||||
|
// Sorted Set expiration maintenance
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
conn.zRemRangeByScore(key, 0, currentTime);
|
||||||
|
|
||||||
|
List<byte[]> byteList;
|
||||||
|
Long size = conn.zCard(key);
|
||||||
|
assert size != null;
|
||||||
|
byteList = new ArrayList<>(size.intValue());
|
||||||
|
Cursor<RedisZSetCommands.Tuple> cursor = conn.zScan(key, ScanOptions.NONE);
|
||||||
|
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
RedisZSetCommands.Tuple t = cursor.next();
|
||||||
|
|
||||||
|
// Probably not necessary because of the maintenance at the beginning but why
|
||||||
|
// not...
|
||||||
|
if (t.getScore() == -1 || t.getScore() > currentTime) {
|
||||||
|
byteList.add(t.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return byteList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a maintenance of the RedisTokenStore.
|
||||||
|
* <p>
|
||||||
|
* SortedSets UNAME_TO_ACCESS and CLIENT_ID_TO_ACCESS contains access tokens that can
|
||||||
|
* expire. This expiration is set as a score of the Redis SortedSet data structure.
|
||||||
|
* Redis does not support expiration of items in a container data structure. It
|
||||||
|
* supports only expiration of whole key. In case there is still new access tokens
|
||||||
|
* being stored into the RedisTokenStore before whole key gets expired, the expiration
|
||||||
|
* is prolonged and the key is not effectively deleted. To do "garbage collection"
|
||||||
|
* this method should be called once upon a time.
|
||||||
|
* @return how many items were removed
|
||||||
|
*/
|
||||||
|
public long doMaintenance() {
|
||||||
|
long removed = 0;
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
// client_id_to_acccess maintenance
|
||||||
|
Cursor<byte[]> clientToAccessKeys = conn
|
||||||
|
.scan(ScanOptions.scanOptions().match(prefix + CLIENT_ID_TO_ACCESS + "*").build());
|
||||||
|
while (clientToAccessKeys.hasNext()) {
|
||||||
|
byte[] clientIdToAccessKey = clientToAccessKeys.next();
|
||||||
|
|
||||||
|
removed += conn.zRemRangeByScore(clientIdToAccessKey, 0, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
// uname_to_access maintenance
|
||||||
|
Cursor<byte[]> unameToAccessKeys = conn
|
||||||
|
.scan(ScanOptions.scanOptions().match(prefix + UNAME_TO_ACCESS + "*").build());
|
||||||
|
while (unameToAccessKeys.hasNext()) {
|
||||||
|
byte[] unameToAccessKey = unameToAccessKeys.next();
|
||||||
|
|
||||||
|
removed += conn.zRemRangeByScore(unameToAccessKey, 0, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String clientId, String userName) {
|
||||||
|
byte[] approvalKey = serializeKey(UNAME_TO_ACCESS + getApprovalKey(clientId, userName));
|
||||||
|
List<byte[]> byteList;
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
byteList = getZByteLists(approvalKey, conn);
|
||||||
|
}
|
||||||
|
if (byteList.size() == 0) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
List<OAuth2AccessToken> accessTokens = new ArrayList<>(byteList.size());
|
||||||
|
for (byte[] bytes : byteList) {
|
||||||
|
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
|
||||||
|
accessTokens.add(accessToken);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableCollection(accessTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<OAuth2AccessToken> findTokensByClientId(String clientId) {
|
||||||
|
byte[] key = serializeKey(CLIENT_ID_TO_ACCESS + clientId);
|
||||||
|
List<byte[]> byteList;
|
||||||
|
try (RedisConnection conn = getConnection()) {
|
||||||
|
byteList = getZByteLists(key, conn);
|
||||||
|
}
|
||||||
|
if (byteList.size() == 0) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
List<OAuth2AccessToken> accessTokens = new ArrayList<>(byteList.size());
|
||||||
|
for (byte[] bytes : byteList) {
|
||||||
|
OAuth2AccessToken accessToken = deserializeAccessToken(bytes);
|
||||||
|
accessTokens.add(accessToken);
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableCollection(accessTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,19 +17,12 @@
|
|||||||
package com.pig4cloud.pig.common.security.component;
|
package com.pig4cloud.pig.common.security.component;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
|
||||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
@ -60,32 +53,9 @@ public class PigResourceServerAutoConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
@Primary
|
||||||
@LoadBalanced
|
public ResourceServerTokenServices resourceServerTokenServices(TokenStore tokenStore,
|
||||||
public RestTemplate lbRestTemplate() {
|
UserDetailsService userDetailsService) {
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
return new PigLocalResourceServerTokenServices(tokenStore, userDetailsService);
|
||||||
|
|
||||||
// 传递ACCEPT JSON
|
|
||||||
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
|
|
||||||
request.getHeaders().set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
return execution.execute(request, body);
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 处理400 异常
|
|
||||||
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public void handleError(ClientHttpResponse response) {
|
|
||||||
// 当认证中心返回 400 或者 424 错误码不抛异常,交给资源服务自行处理
|
|
||||||
if (response.getRawStatusCode() == HttpStatus.FAILED_DEPENDENCY.value()
|
|
||||||
|| response.getRawStatusCode() == HttpStatus.BAD_REQUEST.value()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 原有异常处理逻辑
|
|
||||||
super.handleError(response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return restTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
||||||
import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
|
|
||||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
||||||
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author lengleng
|
* @author lengleng
|
||||||
@ -52,10 +50,10 @@ public class PigResourceServerConfigurerAdapter extends ResourceServerConfigurer
|
|||||||
private PermitAllUrlProperties permitAllUrl;
|
private PermitAllUrlProperties permitAllUrl;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RestTemplate lbRestTemplate;
|
private PigBearerTokenExtractor pigBearerTokenExtractor;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PigBearerTokenExtractor pigBearerTokenExtractor;
|
private ResourceServerTokenServices resourceServerTokenServices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认的配置,对外暴露
|
* 默认的配置,对外暴露
|
||||||
@ -74,14 +72,8 @@ public class PigResourceServerConfigurerAdapter extends ResourceServerConfigurer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(ResourceServerSecurityConfigurer resources) {
|
public void configure(ResourceServerSecurityConfigurer resources) {
|
||||||
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
|
|
||||||
UserAuthenticationConverter userTokenConverter = new PigUserAuthenticationConverter();
|
|
||||||
accessTokenConverter.setUserTokenConverter(userTokenConverter);
|
|
||||||
|
|
||||||
remoteTokenServices.setRestTemplate(lbRestTemplate);
|
|
||||||
remoteTokenServices.setAccessTokenConverter(accessTokenConverter);
|
|
||||||
resources.authenticationEntryPoint(resourceAuthExceptionEntryPoint).tokenExtractor(pigBearerTokenExtractor)
|
resources.authenticationEntryPoint(resourceAuthExceptionEntryPoint).tokenExtractor(pigBearerTokenExtractor)
|
||||||
.accessDeniedHandler(pigAccessDeniedHandler).tokenServices(remoteTokenServices);
|
.accessDeniedHandler(pigAccessDeniedHandler).tokenServices(resourceServerTokenServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.pig4cloud.pig.common.security.component;
|
||||||
|
|
||||||
|
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lengleng
|
||||||
|
* @date 2020/9/29
|
||||||
|
* <p>
|
||||||
|
* redis token store 自动配置
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@EnableScheduling
|
||||||
|
@ConditionalOnBean(AuthorizationServerConfigurerAdapter.class)
|
||||||
|
public class PigTokenStoreAutoCleanSchedule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每小时执行一致,避免 redis zset 容量问题
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "@hourly")
|
||||||
|
public void doMaintenance() {
|
||||||
|
PigRedisTokenStore tokenStore = SpringContextHolder.getBean(PigRedisTokenStore.class);
|
||||||
|
long maintenance = tokenStore.doMaintenance();
|
||||||
|
log.debug("清理Redis ZADD 过期 token 数量: {}", maintenance);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.pig4cloud.pig.common.security.component;
|
||||||
|
|
||||||
|
import com.pig4cloud.pig.common.core.constant.CacheConstants;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author lengleng
|
||||||
|
* @date 2021/10/16
|
||||||
|
*/
|
||||||
|
public class PigTokenStoreAutoConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
PigRedisTokenStore tokenStore = new PigRedisTokenStore(redisConnectionFactory);
|
||||||
|
tokenStore.setPrefix(CacheConstants.PROJECT_OAUTH_ACCESS);
|
||||||
|
return tokenStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.pig4cloud.pig.common.security.component;
|
|
||||||
|
|
||||||
import com.pig4cloud.pig.common.core.constant.SecurityConstants;
|
|
||||||
import com.pig4cloud.pig.common.security.service.PigUser;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
|
||||||
import org.springframework.security.oauth2.provider.token.UserAuthenticationConverter;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lengleng
|
|
||||||
* @date 2019-03-07
|
|
||||||
* <p>
|
|
||||||
* 根据checktoken 的结果转化用户信息
|
|
||||||
*/
|
|
||||||
public class PigUserAuthenticationConverter implements UserAuthenticationConverter {
|
|
||||||
|
|
||||||
private static final String N_A = "N/A";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract information about the user to be used in an access token (i.e. for resource
|
|
||||||
* servers).
|
|
||||||
* @param authentication an authentication representing a user
|
|
||||||
* @return a map of key values representing the unique information about the user
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
|
|
||||||
Map<String, Object> response = new LinkedHashMap<>();
|
|
||||||
response.put(USERNAME, authentication.getName());
|
|
||||||
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
|
|
||||||
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inverse of {@link #convertUserAuthentication(Authentication)}. Extracts an
|
|
||||||
* Authentication from a map.
|
|
||||||
* @param map a map of user information
|
|
||||||
* @return an Authentication representing the user or null if there is none
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Authentication extractAuthentication(Map<String, ?> map) {
|
|
||||||
if (map.containsKey(USERNAME)) {
|
|
||||||
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
|
|
||||||
|
|
||||||
String username = (String) map.get(SecurityConstants.DETAILS_USERNAME);
|
|
||||||
Integer id = (Integer) map.get(SecurityConstants.DETAILS_USER_ID);
|
|
||||||
Integer deptId = (Integer) map.get(SecurityConstants.DETAILS_DEPT_ID);
|
|
||||||
PigUser user = new PigUser(id, deptId, username, N_A, true, true, true, true, authorities);
|
|
||||||
return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
|
|
||||||
Object authorities = map.get(AUTHORITIES);
|
|
||||||
if (authorities instanceof String) {
|
|
||||||
return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
|
|
||||||
}
|
|
||||||
if (authorities instanceof Collection) {
|
|
||||||
return AuthorityUtils.commaSeparatedStringToAuthorityList(
|
|
||||||
StringUtils.collectionToCommaDelimitedString((Collection<?>) authorities));
|
|
||||||
}
|
|
||||||
return AuthorityUtils.NO_AUTHORITIES;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,382 @@
|
|||||||
|
package com.pig4cloud.pig.common.security.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.oauth2.common.*;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
|
||||||
|
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||||
|
import org.springframework.security.oauth2.provider.*;
|
||||||
|
import org.springframework.security.oauth2.provider.token.*;
|
||||||
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义 token 放发处理逻辑
|
||||||
|
*
|
||||||
|
* @author lengleng
|
||||||
|
* @date 2021/10/15
|
||||||
|
*/
|
||||||
|
public class PigCustomTokenServices implements AuthorizationServerTokenServices, ResourceServerTokenServices,
|
||||||
|
ConsumerTokenServices, InitializingBean {
|
||||||
|
|
||||||
|
private int refreshTokenValiditySeconds = 60 * 60 * 24 * 30; // default 30 days.
|
||||||
|
|
||||||
|
private int accessTokenValiditySeconds = 60 * 60 * 12; // default 12 hours.
|
||||||
|
|
||||||
|
private boolean supportRefreshToken = false;
|
||||||
|
|
||||||
|
private boolean reuseRefreshToken = true;
|
||||||
|
|
||||||
|
private TokenStore tokenStore;
|
||||||
|
|
||||||
|
private ClientDetailsService clientDetailsService;
|
||||||
|
|
||||||
|
private TokenEnhancer accessTokenEnhancer;
|
||||||
|
|
||||||
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize these token services. If no random generator is set, one will be
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
public void afterPropertiesSet() {
|
||||||
|
Assert.notNull(tokenStore, "tokenStore must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
|
||||||
|
OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);
|
||||||
|
OAuth2RefreshToken refreshToken = null;
|
||||||
|
|
||||||
|
// 若已产生token , 过期时删除相关token,执行下边的重新生成逻辑
|
||||||
|
if (existingAccessToken != null) {
|
||||||
|
tokenStore.removeAccessToken(existingAccessToken);
|
||||||
|
if (existingAccessToken.getRefreshToken() != null) {
|
||||||
|
refreshToken = existingAccessToken.getRefreshToken();
|
||||||
|
tokenStore.removeRefreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refreshToken == null) {
|
||||||
|
refreshToken = createRefreshToken(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
|
||||||
|
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
|
||||||
|
if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
|
||||||
|
refreshToken = createRefreshToken(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
|
||||||
|
tokenStore.storeAccessToken(accessToken, authentication);
|
||||||
|
|
||||||
|
refreshToken = accessToken.getRefreshToken();
|
||||||
|
if (refreshToken != null) {
|
||||||
|
tokenStore.storeRefreshToken(refreshToken, authentication);
|
||||||
|
}
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(noRollbackFor = { InvalidTokenException.class, InvalidGrantException.class })
|
||||||
|
public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
|
||||||
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
if (!supportRefreshToken) {
|
||||||
|
throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
|
||||||
|
if (refreshToken == null) {
|
||||||
|
throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
|
||||||
|
if (this.authenticationManager != null && !authentication.isClientOnly()) {
|
||||||
|
// The client has already been authenticated, but the user authentication
|
||||||
|
// might be old now, so give it a
|
||||||
|
// chance to re-authenticate.
|
||||||
|
Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "",
|
||||||
|
authentication.getAuthorities());
|
||||||
|
user = authenticationManager.authenticate(user);
|
||||||
|
Object details = authentication.getDetails();
|
||||||
|
authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
|
||||||
|
authentication.setDetails(details);
|
||||||
|
}
|
||||||
|
String clientId = authentication.getOAuth2Request().getClientId();
|
||||||
|
if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
|
||||||
|
throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear out any access tokens already associated with the refresh
|
||||||
|
// token.
|
||||||
|
tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
if (isExpired(refreshToken)) {
|
||||||
|
tokenStore.removeRefreshToken(refreshToken);
|
||||||
|
throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
authentication = createRefreshedAuthentication(authentication, tokenRequest);
|
||||||
|
|
||||||
|
if (!reuseRefreshToken) {
|
||||||
|
tokenStore.removeRefreshToken(refreshToken);
|
||||||
|
refreshToken = createRefreshToken(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
|
||||||
|
tokenStore.storeAccessToken(accessToken, authentication);
|
||||||
|
if (!reuseRefreshToken) {
|
||||||
|
tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
|
||||||
|
}
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
|
||||||
|
return tokenStore.getAccessToken(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a refreshed authentication.
|
||||||
|
* @param authentication The authentication.
|
||||||
|
* @param request The scope for the refreshed token.
|
||||||
|
* @return The refreshed authentication.
|
||||||
|
* @throws InvalidScopeException If the scope requested is invalid or wider than the
|
||||||
|
* original scope.
|
||||||
|
*/
|
||||||
|
private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication,
|
||||||
|
TokenRequest request) {
|
||||||
|
OAuth2Authentication narrowed = authentication;
|
||||||
|
Set<String> scope = request.getScope();
|
||||||
|
OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
|
||||||
|
if (scope != null && !scope.isEmpty()) {
|
||||||
|
Set<String> originalScope = clientAuth.getScope();
|
||||||
|
if (originalScope == null || !originalScope.containsAll(scope)) {
|
||||||
|
throw new InvalidScopeException(
|
||||||
|
"Unable to narrow the scope of the client authentication to " + scope + ".", originalScope);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clientAuth = clientAuth.narrowScope(scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
|
||||||
|
return narrowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isExpired(OAuth2RefreshToken refreshToken) {
|
||||||
|
if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
|
||||||
|
ExpiringOAuth2RefreshToken expiringToken = (ExpiringOAuth2RefreshToken) refreshToken;
|
||||||
|
return expiringToken.getExpiration() == null
|
||||||
|
|| System.currentTimeMillis() > expiringToken.getExpiration().getTime();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuth2AccessToken readAccessToken(String accessToken) {
|
||||||
|
return tokenStore.readAccessToken(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuth2Authentication loadAuthentication(String accessTokenValue)
|
||||||
|
throws AuthenticationException, InvalidTokenException {
|
||||||
|
OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
|
||||||
|
if (accessToken == null) {
|
||||||
|
throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
|
||||||
|
}
|
||||||
|
else if (accessToken.isExpired()) {
|
||||||
|
tokenStore.removeAccessToken(accessToken);
|
||||||
|
throw new InvalidTokenException("Access token expired: " + accessTokenValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
OAuth2Authentication result = tokenStore.readAuthentication(accessToken);
|
||||||
|
if (result == null) {
|
||||||
|
// in case of race condition
|
||||||
|
throw new InvalidTokenException("Invalid access token: " + accessTokenValue);
|
||||||
|
}
|
||||||
|
if (clientDetailsService != null) {
|
||||||
|
String clientId = result.getOAuth2Request().getClientId();
|
||||||
|
try {
|
||||||
|
clientDetailsService.loadClientByClientId(clientId);
|
||||||
|
}
|
||||||
|
catch (ClientRegistrationException e) {
|
||||||
|
throw new InvalidTokenException("Client not valid: " + clientId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId(String tokenValue) {
|
||||||
|
OAuth2Authentication authentication = tokenStore.readAuthentication(tokenValue);
|
||||||
|
if (authentication == null) {
|
||||||
|
throw new InvalidTokenException("Invalid access token: " + tokenValue);
|
||||||
|
}
|
||||||
|
OAuth2Request clientAuth = authentication.getOAuth2Request();
|
||||||
|
if (clientAuth == null) {
|
||||||
|
throw new InvalidTokenException("Invalid access token (no client id): " + tokenValue);
|
||||||
|
}
|
||||||
|
return clientAuth.getClientId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean revokeToken(String tokenValue) {
|
||||||
|
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
|
||||||
|
if (accessToken == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (accessToken.getRefreshToken() != null) {
|
||||||
|
tokenStore.removeRefreshToken(accessToken.getRefreshToken());
|
||||||
|
}
|
||||||
|
tokenStore.removeAccessToken(accessToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
|
||||||
|
if (!isSupportRefreshToken(authentication.getOAuth2Request())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int validitySeconds = getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
|
||||||
|
String value = UUID.randomUUID().toString();
|
||||||
|
if (validitySeconds > 0) {
|
||||||
|
return new DefaultExpiringOAuth2RefreshToken(value,
|
||||||
|
new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
|
||||||
|
}
|
||||||
|
return new DefaultOAuth2RefreshToken(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
|
||||||
|
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
|
||||||
|
int validitySeconds = getAccessTokenValiditySeconds(authentication.getOAuth2Request());
|
||||||
|
if (validitySeconds > 0) {
|
||||||
|
token.setExpiration(new Date(System.currentTimeMillis() + (validitySeconds * 1000L)));
|
||||||
|
}
|
||||||
|
token.setRefreshToken(refreshToken);
|
||||||
|
token.setScope(authentication.getOAuth2Request().getScope());
|
||||||
|
|
||||||
|
return accessTokenEnhancer != null ? accessTokenEnhancer.enhance(token, authentication) : token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The access token validity period in seconds
|
||||||
|
* @param clientAuth the current authorization request
|
||||||
|
* @return the access token validity period in seconds
|
||||||
|
*/
|
||||||
|
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
|
||||||
|
if (clientDetailsService != null) {
|
||||||
|
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||||
|
Integer validity = client.getAccessTokenValiditySeconds();
|
||||||
|
if (validity != null) {
|
||||||
|
return validity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accessTokenValiditySeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The refresh token validity period in seconds
|
||||||
|
* @param clientAuth the current authorization request
|
||||||
|
* @return the refresh token validity period in seconds
|
||||||
|
*/
|
||||||
|
protected int getRefreshTokenValiditySeconds(OAuth2Request clientAuth) {
|
||||||
|
if (clientDetailsService != null) {
|
||||||
|
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||||
|
Integer validity = client.getRefreshTokenValiditySeconds();
|
||||||
|
if (validity != null) {
|
||||||
|
return validity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return refreshTokenValiditySeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a refresh token supported for this client (or the global setting if
|
||||||
|
* {@link #setClientDetailsService(ClientDetailsService) clientDetailsService} is not
|
||||||
|
* set.
|
||||||
|
* @param clientAuth the current authorization request
|
||||||
|
* @return boolean to indicate if refresh token is supported
|
||||||
|
*/
|
||||||
|
protected boolean isSupportRefreshToken(OAuth2Request clientAuth) {
|
||||||
|
if (clientDetailsService != null) {
|
||||||
|
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
|
||||||
|
return client.getAuthorizedGrantTypes().contains("refresh_token");
|
||||||
|
}
|
||||||
|
return this.supportRefreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An access token enhancer that will be applied to a new token before it is saved in
|
||||||
|
* the token store.
|
||||||
|
* @param accessTokenEnhancer the access token enhancer to set
|
||||||
|
*/
|
||||||
|
public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
|
||||||
|
this.accessTokenEnhancer = accessTokenEnhancer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The validity (in seconds) of the refresh token. If less than or equal to zero then
|
||||||
|
* the tokens will be non-expiring.
|
||||||
|
* @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
|
||||||
|
*/
|
||||||
|
public void setRefreshTokenValiditySeconds(int refreshTokenValiditySeconds) {
|
||||||
|
this.refreshTokenValiditySeconds = refreshTokenValiditySeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default validity (in seconds) of the access token. Zero or negative for
|
||||||
|
* non-expiring tokens. If a client details service is set the validity period will be
|
||||||
|
* read from the client, defaulting to this value if not defined by the client.
|
||||||
|
* @param accessTokenValiditySeconds The validity (in seconds) of the access token.
|
||||||
|
*/
|
||||||
|
public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) {
|
||||||
|
this.accessTokenValiditySeconds = accessTokenValiditySeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to support the refresh token.
|
||||||
|
* @param supportRefreshToken Whether to support the refresh token.
|
||||||
|
*/
|
||||||
|
public void setSupportRefreshToken(boolean supportRefreshToken) {
|
||||||
|
this.supportRefreshToken = supportRefreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to reuse refresh tokens (until expired).
|
||||||
|
* @param reuseRefreshToken Whether to reuse refresh tokens (until expired).
|
||||||
|
*/
|
||||||
|
public void setReuseRefreshToken(boolean reuseRefreshToken) {
|
||||||
|
this.reuseRefreshToken = reuseRefreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The persistence strategy for token storage.
|
||||||
|
* @param tokenStore the store for access and refresh tokens.
|
||||||
|
*/
|
||||||
|
public void setTokenStore(TokenStore tokenStore) {
|
||||||
|
this.tokenStore = tokenStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An authentication manager that will be used (if provided) to check the user
|
||||||
|
* authentication when a token is refreshed.
|
||||||
|
* @param authenticationManager the authenticationManager to set
|
||||||
|
*/
|
||||||
|
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
|
||||||
|
this.authenticationManager = authenticationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client details service to use for looking up clients (if necessary). Optional
|
||||||
|
* if the access token expiry is set globally via
|
||||||
|
* {@link #setAccessTokenValiditySeconds(int)}.
|
||||||
|
* @param clientDetailsService the client details service
|
||||||
|
*/
|
||||||
|
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
|
||||||
|
this.clientDetailsService = clientDetailsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl,\
|
com.pig4cloud.pig.common.security.service.PigUserDetailsServiceImpl,\
|
||||||
com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect
|
com.pig4cloud.pig.common.security.component.PigSecurityInnerAspect,\
|
||||||
|
com.pig4cloud.pig.common.security.component.PigTokenStoreAutoConfiguration,\
|
||||||
|
com.pig4cloud.pig.common.security.component.PigTokenStoreAutoCleanSchedule
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-swagger</artifactId>
|
<artifactId>pig-common-swagger</artifactId>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common-test</artifactId>
|
<artifactId>pig-common-test</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-common</artifactId>
|
<artifactId>pig-common</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-gateway</artifactId>
|
<artifactId>pig-gateway</artifactId>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-register</artifactId>
|
<artifactId>pig-register</artifactId>
|
||||||
|
@ -40,7 +40,6 @@ public interface ConfigConstants {
|
|||||||
*/
|
*/
|
||||||
String LOG_BASEDIR = "server.tomcat.basedir";
|
String LOG_BASEDIR = "server.tomcat.basedir";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* access_log日志开关
|
* access_log日志开关
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-upms</artifactId>
|
<artifactId>pig-upms</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-upms-api</artifactId>
|
<artifactId>pig-upms-api</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-upms</artifactId>
|
<artifactId>pig-upms</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-upms-biz</artifactId>
|
<artifactId>pig-upms-biz</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-upms</artifactId>
|
<artifactId>pig-upms</artifactId>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-visual</artifactId>
|
<artifactId>pig-visual</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-codegen</artifactId>
|
<artifactId>pig-codegen</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-visual</artifactId>
|
<artifactId>pig-visual</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-monitor</artifactId>
|
<artifactId>pig-monitor</artifactId>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-visual</artifactId>
|
<artifactId>pig-visual</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-sentinel-dashboard</artifactId>
|
<artifactId>pig-sentinel-dashboard</artifactId>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig-visual</artifactId>
|
<artifactId>pig-visual</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-xxl-job-admin</artifactId>
|
<artifactId>pig-xxl-job-admin</artifactId>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>pig-visual</artifactId>
|
<artifactId>pig-visual</artifactId>
|
||||||
|
26
pom.xml
26
pom.xml
@ -22,7 +22,7 @@
|
|||||||
<groupId>com.pig4cloud</groupId>
|
<groupId>com.pig4cloud</groupId>
|
||||||
<artifactId>pig</artifactId>
|
<artifactId>pig</artifactId>
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
<version>3.3.5</version>
|
<version>3.4.0</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<url>https://www.pig4cloud.com</url>
|
<url>https://www.pig4cloud.com</url>
|
||||||
|
|
||||||
@ -34,9 +34,9 @@
|
|||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
<spring-boot-admin.version>2.5.2</spring-boot-admin.version>
|
<spring-boot-admin.version>2.5.2</spring-boot-admin.version>
|
||||||
<hutool.version>5.7.13</hutool.version>
|
<hutool.version>5.7.14</hutool.version>
|
||||||
<dynamic-ds.version>3.4.1</dynamic-ds.version>
|
<dynamic-ds.version>3.4.1</dynamic-ds.version>
|
||||||
<captcha.version>2.2.0</captcha.version>
|
<captcha.version>2.2.1</captcha.version>
|
||||||
<velocity.version>1.7</velocity.version>
|
<velocity.version>1.7</velocity.version>
|
||||||
<configuration.version>1.10</configuration.version>
|
<configuration.version>1.10</configuration.version>
|
||||||
<nacos.version>2.0.3</nacos.version>
|
<nacos.version>2.0.3</nacos.version>
|
||||||
@ -49,8 +49,8 @@
|
|||||||
<docker.namespace>pig4cloud</docker.namespace>
|
<docker.namespace>pig4cloud</docker.namespace>
|
||||||
<docker.username>username</docker.username>
|
<docker.username>username</docker.username>
|
||||||
<docker.password>password</docker.password>
|
<docker.password>password</docker.password>
|
||||||
<git.commit.plugin>2.2.5</git.commit.plugin>
|
<git.commit.plugin>5.0.0</git.commit.plugin>
|
||||||
<spring.checkstyle.plugin>0.0.28</spring.checkstyle.plugin>
|
<spring.checkstyle.plugin>0.0.29</spring.checkstyle.plugin>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<!-- 以下依赖 全局所有的模块都会引入 -->
|
<!-- 以下依赖 全局所有的模块都会引入 -->
|
||||||
@ -203,9 +203,21 @@
|
|||||||
<plugins>
|
<plugins>
|
||||||
<!--打包jar 与git commit 关联插件-->
|
<!--打包jar 与git commit 关联插件-->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>pl.project13.maven</groupId>
|
<groupId>io.github.git-commit-id</groupId>
|
||||||
<artifactId>git-commit-id-plugin</artifactId>
|
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||||
<version>${git.commit.plugin}</version>
|
<version>${git.commit.plugin}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>get-the-git-infos</id>
|
||||||
|
<goals>
|
||||||
|
<goal>revision</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>initialize</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<generateGitPropertiesFile>true</generateGitPropertiesFile>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<!--代码格式插件,默认使用spring 规则-->
|
<!--代码格式插件,默认使用spring 规则-->
|
||||||
<plugin>
|
<plugin>
|
||||||
|
Loading…
Reference in New Issue
Block a user