轉載請表明出處 https://blog.csdn.net/Amor_Leo/article/details/101751690 謝謝
SpringCloud+OAuth2+Spring Security+Redis+Jwt+Gateway/zuul實現的微服務統一認證授權
源碼
代碼太多了,貼的不完整 ,可以看我上傳到github裏的☞☞ 源碼
推薦看V3的
搭建
OAuth 2.0 簡單介紹
理解Oauth2可以看 阮一峯 理解Oauth
角色
先區分下OAuth 2.0 中有哪些角色,阮一峯博客裏寫的更精確:
Client: 客戶端,也就是Third-party application - 第三方應用程序
Service:服務端,也就是服務的提供者
User: 用戶,也就是Resource Owner - 資源所有者
User Agent:用戶代理,如瀏覽器,下文中將其與Client合併考慮。
Authorization Server:認證服務器,即服務提供商專門用來處理認證的服務器。
Resource Server:資源服務器,即服務提供商存放用戶生成的資源的服務器。
客戶端的授權模式
客戶端必
須得到用戶的授權(authorization grant),才能獲得令牌(access token)。OAuth 2.0定義了四種授權方式。
授權碼模式(authorization code)
簡化模式(implicit)
密碼模式(resource owner password credentials)
客戶端模式(client credentials)
AuthorizationServer 授權服務接口介紹
/oauth/authorize:驗證接口, AuthorizationEndpoint
/oauth/token:獲取token
/oauth/confirm_access:用戶授權
/oauth/error:認證失敗
/oauth/check_token:資源服務器用來校驗token
/oauth/token_key:jwt模式下獲取公鑰;位於:TokenKeyEndpoint ,通過 JwtAccessTokenConverter 訪問key
JWT 簡介
規範
JWT – Json Web Token, 如其名,使用Json方式保存Web Token的協議。網上有各種解讀,個人理解,這就是一個 客戶端Session - Session保存在客戶端,而不是通常的保存在服務端。
構成
JWT三部分組成:
Header 頭部:JSON方式描述JWT基本信息,如類型和簽名算法。使用Base64編碼爲字符串
Payload 載荷:JSON方式描述JWT信息,除了標準定義的,還可以添加自定義的信息。同樣使用Base64編碼爲字符串。
iss: 簽發者
sub: 用戶
aud: 接收方
exp(expires): unix時間戳描述的過期時間
iat(issued at): unix時間戳描述的簽發時間
Signature 簽名:將前兩個字符串用 . 連接後,使用頭部定義的加密算法,利用密鑰進行簽名,並將簽名信息附在最後。
搭建
eureka Server就不寫了,可以看我另一個博客 SpringCloud Eureka
代碼沒有貼完整,只貼了主要的,感興趣的可以去看我github上的 源碼
zuul網關
pom
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--zuul-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!--security和oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
yml
zuul:
host:
connect-timeout-millis: 20000
socket-timeout-millis: 20000
sensitive-headers: Cookie,Set-Cookie
routes:
auth:
path: /auth/**
service-id: sophia-auth
admin:
path: /admin/**
service-id: sophia-admin
security:
oauth2:
client:
access-token-uri: http://localhost:${server.port}/auth/oauth/token
user-authorization-uri: http://localhost:${server.port}/auth/oauth/authorize
client-id: sophia-admin
client-secret: sophia-admin-secret
resource:
user-info-uri: http://localhost:${server.port}/auth/home/principal
prefer-token-info: false
jwt:
key-value: sophia_oauth_key
# key-uri: http://localhost:${server.port}/auth/oauth/token_key
# key-value跟key-uri:token的驗證可以直接在本地(即本服務)完成,不需要連接wsm-oauth服務認證服務器。
# 注意:如果要使用key-value對稱加密方式,
# 到wsm-oauth服務AuthorizationServerConfig類JwtAccessTokenConverter方法中使用對稱加密方式
# jwt:
# key-value: sophia #對稱加密方式
# key-uri: http://localhost:${server.port}/auth/oauth/token_key #非對稱加密方式 (獲取公鑰)
ribbon:
ReadTimeout: 10000 #請求處理的超時時間
ConnectTimeout: 5000 #請求連接的超時時間
MaxAutoRetries: 1 #對當前實例的重試次數
MaxAutoRetriesNextServer: 2 #切換實例的重試次數
eureka:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 100000
啓動類
@EnableZuulProxy
@EnableDiscoveryClient
@EnableOAuth2Sso
@SpringBootApplication
去掉security的登錄驗證
@Configuration
@EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
認證服務
auth pom
<!--公共配置包 包含base基礎包-->
<dependency>
<groupId>com.scaffolding.sophia</groupId>
<artifactId>sophia_common_config</artifactId>
<version>${sophia-common.version}</version>
</dependency>
<!--公共security包 包含admin api 及 包含base基礎包-->
<!--oauth2 security jwt feign的包-->
<dependency>
<groupId>com.scaffolding.sophia</groupId>
<artifactId>sophia_common_security</artifactId>
<version>${sophia-common.version}</version>
</dependency>
<!--actuator監管-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
yml
sophia:
security:
oauth2:
clients[0]:
client_id: sophia-admin
client_secret: sophia-admin-secret
accessTokenValidatySeconds: 21600
refreshTokenValiditySeconds: 28800
clients[1]:
client_id: amor-admin
client_secret: amor-admin-secret
accessTokenValidatySeconds: 21600
refreshTokenValiditySeconds: 28800
web:
loginPage: /index.html
unInterceptUris: /index.html,/static/**,/authentication/form,/authentication/require,/oauth/**,/actuator/**,/druid/*
# 集成了資源服務
# 直接放行URL
ignore:
urls:
- /index.html
- /static/**
- /authentication/form
- /authentication/require
- /oauth/**
- /actuator/**
- /druid/*
ribbon:
ReadTimeout: 10000 #請求處理的超時時間
ConnectTimeout: 5000 #請求連接的超時時間
MaxAutoRetries: 1 #對當前實例的重試次數
MaxAutoRetriesNextServer: 2 #切換實例的重試次數
eureka:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000
#熔斷器開啓
feign:
hystrix:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
認證配置
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.auth.config
* @ClassName: SophiaAuthorizationServerConfig
* @Description: 認證服務
* @Version: 1.0
*/
@Configuration
@EnableAuthorizationServer
public class SophiaAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private SophiaUserDetailService sophiaUserDetailService;
@Autowired
private SophiaSecurityProperties securityProperties;
@Autowired
private RedisConnectionFactory connectionFactory;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 配置客戶端詳情信息,客戶端詳情信息在這裏進行初始化,通過數據庫來存儲調取詳情信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
InMemoryClientDetailsServiceBuilder builder = clients.inMemory();
if (ArrayUtils.isNotEmpty(securityProperties.getOauth2().getClients())) {
for (OAuth2ClientProperties client : securityProperties.getOauth2().getClients()) {
builder
.withClient(client.getClientId())
.secret(new BCryptPasswordEncoder().encode(client.getClientSecret()))
// .resourceIds("admin","auth")
//設置token的有效期,不設置默認12小時
.accessTokenValiditySeconds(client.getAccessTokenValidatySeconds())
//設置刷新token的有效期,不設置默認30天
.refreshTokenValiditySeconds(client.getRefreshTokenValiditySeconds())
.redirectUris("http://www.baidu.com")
.authorizedGrantTypes("authorization_code","client_credentials", "refresh_token", "password")
.scopes("all", "read", "write")
.autoApprove(true);
}
}
}
/**
* 配置授權服務器端點
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
// 自定義jwt生成token方式
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
//指定認證管理器
endpoints.authenticationManager(authenticationManager)
.userDetailsService(sophiaUserDetailService)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
//指定token存儲位置
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter())
// 自定義jwt生成token方式
.tokenEnhancer(tokenEnhancerChain)
// 配置TokenServices參數 如果需要jw的token而不是默認的uuid 那把他註釋
//.tokenServices(defaultTokenServices())
.tokenServices(defaultTokenServices())
.reuseRefreshTokens(false)
// ; //自定義異常處理
.exceptionTranslator(new SophiaWebResponseExceptionTranslator());
}
/**
* 注入自定義token生成方式(jwt)
*/
@Bean
public TokenEnhancer tokenEnhancer() {
return new JwtTokenEnhancer();
}
/**
* 注意,自定義TokenServices的時候,需要設置@Primary,否則報錯
*/
@Primary
@Bean
public DefaultTokenServices defaultTokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
// 這裏如果設置爲false則不能更新refresh_token,如果需要刷新token的功能需要設置成true
tokenServices.setSupportRefreshToken(true);
// 設置上次RefreshToken是否還可以使用 默認爲true
tokenServices.setReuseRefreshToken(false);
// token有效期自定義設置,默認12小時
tokenServices.setAccessTokenValiditySeconds(60 * 60 * 6);
// refresh_token默認30天
tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 8);
tokenServices.setTokenEnhancer(tokenEnhancer());
return tokenServices;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
// 開啓/oauth/token_key驗證端口無權限訪問
.tokenKeyAccess("permitAll()")
// 開啓/oauth/check_token驗證端口認證權限訪問
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(passwordEncoder)
//允許表單認證
.allowFormAuthenticationForClients();
}
/**
* 對Jwt簽名時,增加一個密鑰
* JwtAccessTokenConverter:對Jwt來進行編碼以及解碼的類
*/
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
//測試用,資源服務使用相同的字符達到一個對稱加密的效果,生產時候使用RSA非對稱加密方式
accessTokenConverter.setSigningKey(GlobalsConstants.OAUTH_SIGNING_KEY);
return accessTokenConverter;
}
/**
* token store
*/
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(connectionFactory);
}
}
security 配置
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.auth.config
* @ClassName: SophiaWebSecurityConfig
* @Description: web security 訪問安全配置
* @Version: 1.0
*/
@EnableWebSecurity
@Configuration
@AutoConfigureBefore({SophiaResourceServerConfig.class, SophiaAuthorizationServerConfig.class})
public class SophiaWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SophiaUserDetailService sophiaUserDetailService;
@Autowired
private SophiaSecurityProperties securityProperties;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.anyRequest()
.and()
.authorizeRequests()
.antMatchers(securityProperties.getWeb().getUnInterceptUris())
.permitAll()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf()
.disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(sophiaUserDetailService).passwordEncoder(new BCryptPasswordEncoder());
}
}
資源服務
資源服務是寫成公共的 認證服務和用戶服務以及其他服務需要集成它
資源服務配置
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.common.security.config
* @ClassName: SophiaResourceServerConfig
* @Description: 資源服務 資源訪問權限配置: 給接口地址讓security管理起來,如哪些不需要授權能訪問;哪些需要登錄授權後能訪問,哪些需要用戶擁有這些角色才能訪問。
* 優先級低於AuthorizationServerConfigurerAdapter
* @Version: 1.0
*/
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("com.scaffolding.sophia.common.security")
public class SophiaResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private FilterIgnoreProperties ignorePropertiesConfig;
@Autowired
private RedisConnectionFactory redisConnectionFactory;
/**
* 對Jwt簽名時,增加一個密鑰
* JwtAccessTokenConverter:對Jwt來進行編碼以及解碼的類
*/
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
//對稱加密方式 測試用,資源服務使用相同的字符達到一個對稱加密的效果,生產時候使用RSA非對稱加密方式
jwtAccessTokenConverter.setSigningKey(GlobalsConstants.OAUTH_SIGNING_KEY);
return jwtAccessTokenConverter;
}
/**
* token store
*/
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
@Override
@SneakyThrows
public void configure(HttpSecurity httpSecurity) {
//允許使用iframe 嵌套,避免swagger-ui 不被加載的問題
httpSecurity.headers().frameOptions().disable();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>
.ExpressionInterceptUrlRegistry registry = httpSecurity
.authorizeRequests();
//對配置的url放行 不進行驗證
ignorePropertiesConfig.getUrls()
.forEach(url -> registry.antMatchers(url).permitAll());
registry.anyRequest().authenticated()
.and().csrf().disable();
}
@Override
@CrossOrigin
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.tokenStore(tokenStore())
//自定義Token異常信息,用於token校驗失敗返回信息
.authenticationEntryPoint(new MyAuthExceptionEntryPoint())
//授權異常處理
.accessDeniedHandler(new MyAccessDeniedHandler());
}
}
自定義生成jwt
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.common.security.config
* @ClassName: JwtTokenEnhancer
* @Description: 自定義token生成攜帶的信息
* @Version: 1.0
*/
@Component
public class JwtTokenEnhancer implements TokenEnhancer {
// private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
final Map<String, Object> additionalInfo = new HashMap<>();
// 給/oauth/token接口加屬性roles,author
JSONObject jsonObject = new JSONObject(authentication.getPrincipal());
List<Object> authorities = jsonObject.getJSONArray("authorities").toList();
StringBuilder stringBuilder = new StringBuilder();
for (Object authority : authorities) {
Map map = (Map) authority;
stringBuilder.append(map.get("authority"));
stringBuilder.append(",");
}
String roles = stringBuilder.toString();
additionalInfo.put("roles", roles.substring(0, roles.length() - 1));
additionalInfo.put("author", "sophia");
// additionalInfo.put("createTime", df.format(LocalDateTime.now()));
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
UserDetailsService
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.common.security.service
* @ClassName: SophiaUserDetailService
* @Description: 用戶登錄 查詢登錄用戶 使用feign調用用戶服務暴露的接口 這裏面的兩個接口需要過濾 不驗證
* @Version: 1.0
*/
@Component
public class SophiaUserDetailService implements UserDetailsService {
@Autowired
private UserClient userClient;
@Autowired
private AuthorityClient authorityClient;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if(StringUtils.isEmpty(username)){
throw new CommonException("登錄名不能爲空");
}
ApiResponse apiResponse = userClient.getUserByUserName(username);
User user = JSON.parseObject(JSON.toJSONString( apiResponse.getData(), true),User.class);
if (user == null) {
throw new CommonException("登錄名不存在");
} else if (BizConstants.USER_STATUS_EXPIRED.equals(user.getStatus())) {
throw new CommonException("用戶已過期");
} else if (BizConstants.USER_STATUS_LOCKED.equals(user.getStatus())) {
throw new CommonException("用戶已鎖定");
} else if (BizConstants.USER_STATUS_UNUSED.equals(user.getStatus())) {
throw new CommonException("用戶已禁用");
}
ApiResponse response = authorityClient.getAuthorityByUserId(user.getId());
List<Authority> authList = JSON.parseArray(JSON.toJSONString(response.getData(), true),Authority.class);
List<GrantedAuthority> lists = new ArrayList<>();
if(authList != null && authList.size()>0){
for (Authority auth : authList) {
lists.add(new SimpleGrantedAuthority(auth.getAuthCode()));
}
}
//數據庫密碼是加密的
LoginUser loginUser = new LoginUser(username,user.getPassword(),user.getNickname(),user.getStatus(), lists);
// LoginUser loginUser = new LoginUser(username,passwordEncoder.encode(user.getPassword()),user.getNickname(),user.getStatus(), lists);
loginUser.setId(user.getId());
loginUser.setDeptId(user.getDeptId());
return loginUser;
}
}
因爲查詢用戶信息使用了feign,會有一些坑,比如token沒有傳遞下來,token失效等等
feign配置
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.common.feign
* @ClassName: FeignRequestInterceptorConfig
* @Description:
* @Version: 1.0
*/
@Component
public class FeignRequestInterceptorConfig implements RequestInterceptor {
private static final Logger log = LoggerFactory.getLogger(FeignRequestInterceptorConfig.class);
private final String AUTHORIZATION_HEADER = "Authorization";
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
if (request != null) {
log.error("調用feign傳遞header攜帶token");
// 只攜帶token
// String authorization = request.getHeader(AUTHORIZATION_HEADER);
// requestTemplate.header("Authorization", authorization);
// System.err.println("Authorization :\t\t"+ authorization);
// 攜帶全部
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
requestTemplate.header(name, values);
log.debug("name :\t\t" + name);
log.debug("values : \t\t" + values);
}
}
}
}
}
/**
* @author: LHL
* @ProjectName: sophia_scaffolding
* @Package: com.scaffolding.sophia.common.security.config
* @ClassName: FeignHystrixConcurrencyStrategy
* @Description: 自定義Feign的隔離策略:
* 在轉發Feign的請求頭的時候, 如果開啓了Hystrix,
* Hystrix的默認隔離策略是Thread(線程隔離策略), 因此轉發攔截器內是無法獲取到請求的請求頭信息的,
* 可以修改默認隔離策略爲信號量模式:hystrix.command.default.execution.isolation.strategy=SEMAPHORE,
* 這樣的話轉發線程和請求線程實際上是一個線程, 這並不是最好的解決方法, 信號量模式也不是官方最爲推薦的隔離策略;
* 另一個解決方法就是自定義Hystrix的隔離策略:
* 思路是將現有的併發策略作爲新併發策略的成員變量,在新併發策略中,
* 返回現有併發策略的線程池、Queue;將策略加到Spring容器即可;
* @Version: 1.0
*/
@Configuration
public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class);
private HystrixConcurrencyStrategy delegate;
public FeignHystrixConcurrencyStrategy() {
try {
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {
// Welcome to singleton hell...
return;
}
HystrixCommandExecutionHook commandExecutionHook =
HystrixPlugins.getInstance().getCommandExecutionHook();
HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
HystrixPropertiesStrategy propertiesStrategy =
HystrixPlugins.getInstance().getPropertiesStrategy();
this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
HystrixPlugins.reset();
HystrixPlugins instance = HystrixPlugins.getInstance();
instance.registerConcurrencyStrategy(this);
instance.registerCommandExecutionHook(commandExecutionHook);
instance.registerEventNotifier(eventNotifier);
instance.registerMetricsPublisher(metricsPublisher);
instance.registerPropertiesStrategy(propertiesStrategy);
} catch (Exception e) {
log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
}
}
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
HystrixMetricsPublisher metricsPublisher,
HystrixPropertiesStrategy propertiesStrategy) {
if (log.isDebugEnabled()) {
log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
+ this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
+ metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
}
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return new WrappedCallable<>(callable, requestAttributes);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixProperty<Integer> corePoolSize,
HystrixProperty<Integer> maximumPoolSize,
HystrixProperty<Integer> keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
unit, workQueue);
}
@Override
public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
HystrixThreadPoolProperties threadPoolProperties) {
return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
}
@Override
public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
return this.delegate.getBlockingQueue(maxQueueSize);
}
@Override
public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
return this.delegate.getRequestVariable(rv);
}
static class WrappedCallable<T> implements Callable<T> {
private final Callable<T> target;
private final RequestAttributes requestAttributes;
public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
this.target = target;
this.requestAttributes = requestAttributes;
}
@Override
public T call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return target.call();
} finally {
RequestContextHolder.resetRequestAttributes();
}
}
}
}
用戶微服務集成了資源服務
yml
security:
oauth2:
client:
client-id: sophia-admin
client-secret: sophia-admin-secret
resource:
jwt:
key-value: sophia_oauth_key
ribbon:
ReadTimeout: 10000 #請求處理的超時時間
ConnectTimeout: 5000 #請求連接的超時時間
MaxAutoRetries: 1 #對當前實例的重試次數
MaxAutoRetriesNextServer: 2 #切換實例的重試次數
eureka:
enabled: true
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 60000
#熔斷器開啓
feign:
hystrix:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
# 直接放行URL
ignore:
urls:
- /actuator/**
- /user/api/**
- /authority/api/**
資源服務中調用了用戶服務中的api
@FeignClient(contextId = "userClient", name = ServiceNameConstants.SOPHIA_ADMIN, configuration = FeignRequestInterceptorConfig.class, fallback = UserClientFallBack.class)
測試
使用postman
http://localhost:8080/auth/oauth/token?username=admin&password=123456&grant_type=password&client_id=sophia-admin&client_secret=sophia-admin-secret&scope=all
獲取token
請求
設置token
Bearer Token
整合Swaggergateway整合swagger
V1的sql已改 (是我忘記改git的sql了)