转载请表明出处 https://blog.csdn.net/Amor_Leo/article/details/101751690 谢谢
代码太多了,贴的不完整 ,可以看我上传到github里的☞☞ 源码
推荐看V3的
搭建
理解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)
/oauth/authorize:验证接口, AuthorizationEndpoint
/oauth/token:获取token
/oauth/confirm_access:用户授权
/oauth/error:认证失败
/oauth/check_token:资源服务器用来校验token
/oauth/token_key:jwt模式下获取公钥;位于:TokenKeyEndpoint ,通过 JwtAccessTokenConverter 访问key
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上的 源码
pom
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-zuul
org.springframework.cloud
spring-cloud-starter-oauth2
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
com.scaffolding.sophia
sophia_common_config
${sophia-common.version}
com.scaffolding.sophia
sophia_common_security
${sophia-common.version}
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
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
整合Swaggergateway整合swagger
V1的sql已改 (是我忘记改git的sql了)