mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-21 20:37:10 +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)
|
||||
> Github Action: https://github.com/pig-mesh/pig failure
|
||||
> (⋟﹏⋞) 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
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.versionsBackup
|
||||
|
||||
### vscode ###
|
||||
.vscode
|
||||
|
2
LICENSE
2
LICENSE
@ -193,7 +193,7 @@
|
||||
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
|
||||
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,
|
||||
|
34
README.md
34
README.md
@ -13,6 +13,20 @@
|
||||
- 提供对常见容器化支持 Docker、Kubernetes、Rancher2 支持
|
||||
- 提供 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 Security OAuth2 | 2.3.6 |
|
||||
| Mybatis Plus | 3.4.3.5 |
|
||||
| hutool | 5.7.13 |
|
||||
| hutool | 5.7.14 |
|
||||
| Avue | 2.6.18 |
|
||||
|
||||
### 模块说明
|
||||
@ -55,16 +69,6 @@ pig
|
||||
└── 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),包括开发环境安装、服务端代码运行、前端代码运行等。
|
||||
@ -73,7 +77,8 @@ 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)
|
||||
|
||||
### Docker 运行
|
||||
@ -105,11 +110,6 @@ npm run build:docker && docker-compose up -d
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## 微信群 [禁广告]
|
||||
|
||||
![1628762721](https://minio.pigx.vip/oss/1628762721.png)
|
||||
|
||||
|
||||
## 开源共建
|
||||
|
||||
### 开源协议
|
||||
|
@ -12,7 +12,7 @@ services:
|
||||
- 3306:3306
|
||||
|
||||
pig-redis:
|
||||
image: redis:6.0
|
||||
image: redis:6.2.6
|
||||
ports:
|
||||
- 6379:6379
|
||||
restart: always
|
||||
@ -90,4 +90,4 @@ services:
|
||||
hostname: pig-job
|
||||
image: pig-job
|
||||
ports:
|
||||
- 5004:5004
|
||||
- 5004:5004
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-auth</artifactId>
|
||||
|
@ -16,19 +16,19 @@
|
||||
|
||||
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.security.component.PigWebResponseExceptionTranslator;
|
||||
import com.pig4cloud.pig.common.security.grant.ResourceOwnerCustomeAppTokenGranter;
|
||||
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.SneakyThrows;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
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.oauth2.common.DefaultOAuth2AccessToken;
|
||||
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.configurers.AuthorizationServerEndpointsConfigurer;
|
||||
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.TokenGranter;
|
||||
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
|
||||
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 java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@ -63,7 +61,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
||||
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
private final RedisConnectionFactory redisConnectionFactory;
|
||||
private final TokenStore redisTokenStore;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
@ -78,8 +76,8 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
||||
|
||||
@Override
|
||||
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
|
||||
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenStore(tokenStore())
|
||||
.tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService)
|
||||
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST).tokenServices(tokenServices())
|
||||
.tokenStore(redisTokenStore).tokenEnhancer(tokenEnhancer()).userDetailsService(userDetailsService)
|
||||
.authenticationManager(authenticationManager).reuseRefreshTokens(false)
|
||||
.pathMapping("/oauth/confirm_access", "/token/confirm_access")
|
||||
.exceptionTranslator(new PigWebResponseExceptionTranslator());
|
||||
@ -98,33 +96,42 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
|
||||
endpoints.tokenGranter(compositeTokenGranter);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenStore tokenStore() {
|
||||
RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
|
||||
tokenStore.setPrefix(CacheConstants.PROJECT_OAUTH_ACCESS);
|
||||
return tokenStore;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TokenEnhancer tokenEnhancer() {
|
||||
return (accessToken, authentication) -> {
|
||||
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_USER_ID, pigUser.getId());
|
||||
additionalInfo.put(SecurityConstants.DETAILS_USERNAME, pigUser.getUsername());
|
||||
additionalInfo.put(SecurityConstants.DETAILS_DEPT_ID, pigUser.getDeptId());
|
||||
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
|
||||
return accessToken;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PigClientDetailsService pigClientDetailsService() {
|
||||
public ClientDetailsService pigClientDetailsService() {
|
||||
PigClientDetailsService clientDetailsService = new PigClientDetailsService(dataSource);
|
||||
clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
|
||||
clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
|
||||
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>
|
||||
<artifactId>pig-common-bom</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>pig-common-bom</name>
|
||||
@ -20,9 +20,9 @@
|
||||
<security.oauth.version>2.1.8.RELEASE</security.oauth.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<git.commit.plugin>2.2.5</git.commit.plugin>
|
||||
<spring.checkstyle.plugin>0.0.28</spring.checkstyle.plugin>
|
||||
<fastjson.version>1.2.75</fastjson.version>
|
||||
<git.commit.plugin>5.0.0</git.commit.plugin>
|
||||
<spring.checkstyle.plugin>0.0.29</spring.checkstyle.plugin>
|
||||
<fastjson.version>1.2.78</fastjson.version>
|
||||
<swagger.core.version>1.5.24</swagger.core.version>
|
||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||
<nacos.version>2.0.3</nacos.version>
|
||||
@ -150,8 +150,8 @@
|
||||
<plugins>
|
||||
<!--打包jar 与git commit 关联插件-->
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>${git.commit.plugin}</version>
|
||||
</plugin>
|
||||
<!--代码格式插件,默认使用spring 规则-->
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-core</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-job</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-log</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-mybatis</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<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;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.SneakyThrows;
|
||||
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.Primary;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@ -60,32 +53,9 @@ public class PigResourceServerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@LoadBalanced
|
||||
public RestTemplate lbRestTemplate() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// 传递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;
|
||||
public ResourceServerTokenServices resourceServerTokenServices(TokenStore tokenStore,
|
||||
UserDetailsService userDetailsService) {
|
||||
return new PigLocalResourceServerTokenServices(tokenStore, userDetailsService);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||
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.UserAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@ -52,10 +50,10 @@ public class PigResourceServerConfigurerAdapter extends ResourceServerConfigurer
|
||||
private PermitAllUrlProperties permitAllUrl;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate lbRestTemplate;
|
||||
private PigBearerTokenExtractor pigBearerTokenExtractor;
|
||||
|
||||
@Autowired
|
||||
private PigBearerTokenExtractor pigBearerTokenExtractor;
|
||||
private ResourceServerTokenServices resourceServerTokenServices;
|
||||
|
||||
/**
|
||||
* 默认的配置,对外暴露
|
||||
@ -74,14 +72,8 @@ public class PigResourceServerConfigurerAdapter extends ResourceServerConfigurer
|
||||
|
||||
@Override
|
||||
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)
|
||||
.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=\
|
||||
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>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-swagger</artifactId>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common-test</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-common</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-gateway</artifactId>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-register</artifactId>
|
||||
|
@ -40,7 +40,6 @@ public interface ConfigConstants {
|
||||
*/
|
||||
String LOG_BASEDIR = "server.tomcat.basedir";
|
||||
|
||||
|
||||
/**
|
||||
* access_log日志开关
|
||||
*/
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-upms</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-upms-api</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-upms</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-upms-biz</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-upms</artifactId>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-visual</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-codegen</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-visual</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-monitor</artifactId>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-visual</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-sentinel-dashboard</artifactId>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-visual</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-xxl-job-admin</artifactId>
|
||||
|
@ -21,7 +21,7 @@
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>pig-visual</artifactId>
|
||||
|
26
pom.xml
26
pom.xml
@ -22,7 +22,7 @@
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>3.3.5</version>
|
||||
<version>3.4.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<url>https://www.pig4cloud.com</url>
|
||||
|
||||
@ -34,9 +34,9 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<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>
|
||||
<captcha.version>2.2.0</captcha.version>
|
||||
<captcha.version>2.2.1</captcha.version>
|
||||
<velocity.version>1.7</velocity.version>
|
||||
<configuration.version>1.10</configuration.version>
|
||||
<nacos.version>2.0.3</nacos.version>
|
||||
@ -49,8 +49,8 @@
|
||||
<docker.namespace>pig4cloud</docker.namespace>
|
||||
<docker.username>username</docker.username>
|
||||
<docker.password>password</docker.password>
|
||||
<git.commit.plugin>2.2.5</git.commit.plugin>
|
||||
<spring.checkstyle.plugin>0.0.28</spring.checkstyle.plugin>
|
||||
<git.commit.plugin>5.0.0</git.commit.plugin>
|
||||
<spring.checkstyle.plugin>0.0.29</spring.checkstyle.plugin>
|
||||
</properties>
|
||||
|
||||
<!-- 以下依赖 全局所有的模块都会引入 -->
|
||||
@ -203,9 +203,21 @@
|
||||
<plugins>
|
||||
<!--打包jar 与git commit 关联插件-->
|
||||
<plugin>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<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>
|
||||
<!--代码格式插件,默认使用spring 规则-->
|
||||
<plugin>
|
||||
|
Loading…
Reference in New Issue
Block a user