一,单点登陆概述html
(一)什么是单点登陆:每一个子系统从第三方认证系统中查找而不是每一个系统都经过各自的session校验。java
(三)单点登陆实现框架:mysql
apache Shiroweb
CASredis
springsecurity算法
二。Oauth2认证微信认证第三方登陆spring
1.受权码模式:资源拥有者(用户)发起微信登陆,平台调用微信接口,到达受权页面,手机wx扫码登陆用户赞成受权,微信会对用户进行验证,经过后给平台一个受权码,平台sql
携带受权码到微信认证服务申请令牌,并返回令牌到平台,平台再携带令牌调微信用户信息服务,微信用户信息服务校验令牌合法性,响应给平台,apache
平台显示微信头像。json
客户端(平台)拿到受权码去认证服务申请令牌,受权服务经过私钥加密生成令牌,
令牌给客户端,携带令牌访问资源服务
课程服务至关于资源存储公钥(根据公钥校验令牌合法性===公钥把令牌解开,放行;;解不开拒绝服务)
课程服务至关于资源服务
对swagger进行放行
"/swagger-resources","/swagger-resources/configuration/security", "/swagger-ui.html","/webjars/**","/course/coursepic/list/*").permitAll()
mport org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.stream.Collectors; @Configuration @EnableResourceServer @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)//激活方法上的PreAuthorize注解 public class ResourceServerConfig extends ResourceServerConfigurerAdapter { //公钥 private static final String PUBLIC_KEY = "publickey.txt"; //定义JwtTokenStore,使用jwt令牌 @Bean public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); } //定义JJwtAccessTokenConverter,使用jwt令牌 @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setVerifierKey(getPubKey()); return converter; } /** * 获取非对称加密公钥 Key * @return 公钥 Key */ private String getPubKey() { Resource resource = new ClassPathResource(PUBLIC_KEY); try { InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream()); BufferedReader br = new BufferedReader(inputStreamReader); return br.lines().collect(Collectors.joining("\n")); } catch (IOException ioe) { return null; } } //Http安全配置,对每一个到达系统的http请求连接进行校验 @Override public void configure(HttpSecurity http) throws Exception { //全部请求必须认证经过 http.authorizeRequests() .antMatchers("/v2/api-docs", "/swagger-resources/configuration/ui", "/swagger-resources","/swagger-resources/configuration/security", "/swagger-ui.html","/webjars/**","/course/coursepic/list/*").permitAll() .anyRequest().authenticated(); } }
访问课程服务只有:头部KEY:authorization
value:Bear+accesstoken
才能够访问
2.密码算法模式
不用申请受权码,用户名,密码就能够;
jwt中包含了用户信息,能够避免资源服务解决不了验证还要请求认证服务来验证。效率高
是个json串便于解析,易拓展,非对称安全,但长
分为头部(加密算法),负载(本身加),签名(认证服务端签发的惟一防止窃取)。
(一)认证服务的controller
如何申请令牌
clientid,clientpassword
bodyheader封装在HTTPentity
getHttpBasic
MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("grant_type","password"); body.add("username","itcast"); body.add("password","123"); MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); headers.add("Authorization",this.getHttpBasic("XcWebApp","XcWebApp")); HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body,headers);
private String getHttpBasic(String clientId, String clientPassword) {
String value =clientId+":"+clientPassword ;
byte[] encode = Base64Utils.encode(value.getBytes());
return "Basic "+new String(encode);
}
uri
//http://localhost:40400/auth/oauth/token ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH); // http://localhost:40400 URI uri = serviceInstance.getUri(); String url = uri+"/auth/oauth/token";
ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);
Map map = responseEntity.getBody();
1 Override 2 @PostMapping("/userlogin") 3 public LoginResult login(LoginRequest loginRequest) { 4 5 //判断参数 6 if (StringUtils.isEmpty(loginRequest.getUsername())){ 7 ExceptionCast.cast(AuthCode.AUTH_USERNAME_NONE); 8 } 9 if (StringUtils.isEmpty(loginRequest.getPassword())){ 10 ExceptionCast.cast(AuthCode.AUTH_PASSWORD_NONE); 11 } 12 13 //申请令牌 14 AuthToken authToken = authService.login(loginRequest.getUsername(),loginRequest.getPassword(),clientId,clientSecret); 15 16 String jti = authToken.getJti(); 17 18 //将令牌信息存入cookie 19 this.saveTokenToCookie(jti); 20 21 return new LoginResult(CommonCode.SUCCESS,jti); 22 } 23 24 private void saveTokenToCookie(String jti) { 25 HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); 26 27 //httpOnly:false。 容许浏览器获取cookie 28 CookieUtil.addCookie(response,cookieDomain,"/","uid",jti,cookieMaxAge,false); 29 }
测试
实际结果
(二)认证服务的service
public AuthToken login(String username, String password, String clientId, String clientSecret) { //申请令牌 AuthToken authToken = this.applyToken(username,password,clientId,clientSecret); //将令牌存入redis boolean result = this.saveTokenToRedis(authToken); if (!result){ //存入失败 ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL); } return authToken; } //存入redis private boolean saveTokenToRedis(AuthToken authToken) { String key = "user_token:"+authToken.getJti(); String tokenString = JSON.toJSONString(authToken); stringRedisTemplate.boundValueOps(key).set(tokenString,tokenValiditySeconds, TimeUnit.SECONDS); Long expire = stringRedisTemplate.getExpire(key); return expire>0; } //申请令牌 private AuthToken applyToken(String username, String password, String clientId, String clientSecret) { ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH); URI uri = serviceInstance.getUri(); String url = uri+"/auth/oauth/token"; MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("grant_type","password"); body.add("username",username); body.add("password",password); MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); headers.add("Authorization",this.getHttpBasic(clientId,clientSecret)); HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(body,headers); restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){ @Override public void handleError(ClientHttpResponse response) throws IOException { if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){ super.handleError(response); } } }); ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class); Map map = responseEntity.getBody(); if (map == null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){ ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL); } AuthToken authToken = new AuthToken(); authToken.setAccess_token((String) map.get("access_token")); authToken.setRefresh_token((String) map.get("refresh_token")); authToken.setJti((String) map.get("jti")); return authToken; }
三,具体单点登陆实现认证服务
(一)配置文件
1
AuthorizationServerConfig
密钥非对称加密,私钥加密,公钥解密
package com.xuecheng.auth.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.bootstrap.encrypt.KeyProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 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.client.JdbcClientDetailsService; import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory; import javax.annotation.Resource; import javax.sql.DataSource; import java.security.KeyPair; @Configuration @EnableAuthorizationServer class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private DataSource dataSource; //jwt令牌转换器 @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired UserDetailsService userDetailsService; @Autowired AuthenticationManager authenticationManager; @Autowired TokenStore tokenStore; @Autowired private CustomUserAuthenticationConverter customUserAuthenticationConverter; //读取密钥的配置 @Bean("keyProp") public KeyProperties keyProperties(){ return new KeyProperties(); } @Resource(name = "keyProp") private KeyProperties keyProperties; //客户端配置 @Bean public ClientDetailsService clientDetails() { return new JdbcClientDetailsService(dataSource); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.jdbc(this.dataSource).clients(this.clientDetails()); /* clients.inMemory() .withClient("XcWebApp")//客户端id .secret("XcWebApp")//密码,要保密 .accessTokenValiditySeconds(60)//访问令牌有效期 .refreshTokenValiditySeconds(60)//刷新令牌有效期 //受权客户端请求认证服务的类型authorization_code:根据受权码生成令牌, // client_credentials:客户端认证,refresh_token:刷新令牌,password:密码方式认证 .authorizedGrantTypes("authorization_code", "client_credentials", "refresh_token", "password") .scopes("app");//客户端范围,名称自定义,必填*/ } //token的存储方法 // @Bean // public InMemoryTokenStore tokenStore() { // //将令牌存储到内存 // return new InMemoryTokenStore(); // } // @Bean // public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory){ // RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory); // return redisTokenStore; // } @Bean @Autowired public TokenStore tokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { return new JwtTokenStore(jwtAccessTokenConverter); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(CustomUserAuthenticationConverter customUserAuthenticationConverter) { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); KeyPair keyPair = new KeyStoreKeyFactory (keyProperties.getKeyStore().getLocation(), keyProperties.getKeyStore().getSecret().toCharArray()) .getKeyPair(keyProperties.getKeyStore().getAlias(),keyProperties.getKeyStore().getPassword().toCharArray()); converter.setKeyPair(keyPair); //配置自定义的CustomUserAuthenticationConverter DefaultAccessTokenConverter accessTokenConverter = (DefaultAccessTokenConverter) converter.getAccessTokenConverter(); accessTokenConverter.setUserTokenConverter(customUserAuthenticationConverter); return converter; } //受权服务器端点配置 @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /*Collection<TokenEnhancer> tokenEnhancers = applicationContext.getBeansOfType(TokenEnhancer.class).values(); TokenEnhancerChain tokenEnhancerChain=new TokenEnhancerChain(); tokenEnhancerChain.setTokenEnhancers(new ArrayList<>(tokenEnhancers)); DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setReuseRefreshToken(true); defaultTokenServices.setSupportRefreshToken(true); defaultTokenServices.setTokenStore(tokenStore); defaultTokenServices.setAccessTokenValiditySeconds(1111111); defaultTokenServices.setRefreshTokenValiditySeconds(1111111); defaultTokenServices.setTokenEnhancer(tokenEnhancerChain); endpoints .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) //.tokenStore(tokenStore); .tokenServices(defaultTokenServices);*/ endpoints.accessTokenConverter(jwtAccessTokenConverter) .authenticationManager(authenticationManager)//认证管理器 .tokenStore(tokenStore)//令牌存储 .userDetailsService(userDetailsService);//用户信息service } //受权服务器的安全配置 @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { // oauthServer.checkTokenAccess("isAuthenticated()");//校验token须要认证经过,可采用http basic认证 oauthServer.allowFormAuthenticationForClients() .passwordEncoder(new BCryptPasswordEncoder()) .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } }
2
CustomUserAuthenticationConverter
生成令牌信息
package com.xuecheng.auth.config; import com.xuecheng.auth.service.UserJwt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; import org.springframework.stereotype.Component; import java.util.LinkedHashMap; import java.util.Map; @Component public class CustomUserAuthenticationConverter extends DefaultUserAuthenticationConverter { @Autowired UserDetailsService userDetailsService; @Override public Map<String, ?> convertUserAuthentication(Authentication authentication) { LinkedHashMap response = new LinkedHashMap(); String name = authentication.getName(); response.put("user_name", name); Object principal = authentication.getPrincipal(); UserJwt userJwt = null; if(principal instanceof UserJwt){ userJwt = (UserJwt) principal; }else{ //refresh_token默认不去调用userdetailService获取用户信息,这里咱们手动去调用,获得 UserJwt UserDetails userDetails = userDetailsService.loadUserByUsername(name); userJwt = (UserJwt) userDetails; } response.put("name", userJwt.getName()); response.put("id", userJwt.getId()); response.put("utype",userJwt.getUtype()); response.put("userpic",userJwt.getUserpic()); response.put("companyId",userJwt.getCompanyId()); if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) { response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities())); } return response; } }
3
WebSecurityConfig
对登陆放行
密码加盐加密
1 import org.springframework.context.annotation.Bean; 2 import org.springframework.context.annotation.Configuration; 3 import org.springframework.core.annotation.Order; 4 import org.springframework.security.authentication.AuthenticationManager; 5 import org.springframework.security.config.annotation.web.builders.HttpSecurity; 6 import org.springframework.security.config.annotation.web.builders.WebSecurity; 7 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 9 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 import org.springframework.security.crypto.password.PasswordEncoder; 11 12 @Configuration 13 @EnableWebSecurity 14 @Order(-1) 15 class WebSecurityConfig extends WebSecurityConfigurerAdapter { 16 17 @Override 18 public void configure(WebSecurity web) throws Exception { 19 web.ignoring().antMatchers("/userlogin","/userlogout","/userjwt"); 20 21 } 22 @Bean 23 @Override 24 public AuthenticationManager authenticationManagerBean() throws Exception { 25 AuthenticationManager manager = super.authenticationManagerBean(); 26 return manager; 27 } 28 //采用bcrypt对密码进行编码 29 @Bean 30 public PasswordEncoder passwordEncoder() { 31 return new BCryptPasswordEncoder(); 32 } 33 34 @Override 35 public void configure(HttpSecurity http) throws Exception { 36 http.csrf().disable() 37 .httpBasic().and() 38 .formLogin() 39 .and() 40 .authorizeRequests().anyRequest().authenticated(); 41 42 } 43 }
authservice写认证
package com.xuecheng.auth.service; import com.alibaba.fastjson.JSON; import com.xuecheng.filesystem.framework.client.XcServiceList; import com.xuecheng.filesystem.framework.domain.ucenter.ext.AuthToken; import com.xuecheng.filesystem.framework.domain.ucenter.response.AuthCode; import com.xuecheng.filesystem.framework.exception.ExceptionCast; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Service; import org.springframework.util.Base64Utils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.RestTemplate; import java.io.IOException; import java.net.URI; import java.util.Map; import java.util.concurrent.TimeUnit; @Service public class AuthService { @Autowired private RestTemplate restTemplate; @Autowired private LoadBalancerClient loadBalancerClient; @Autowired private StringRedisTemplate stringRedisTemplate; @Value("${auth.tokenValiditySeconds}") private long tokenValiditySeconds; /** * 用户认证登陆,申请令牌 * @param username * @param password * @param clientId * @param clientSecret * @return */ public AuthToken login(String username, String password, String clientId, String clientSecret) { //申请令牌 AuthToken authToken = this.applyToken(username,password,clientId,clientSecret); //将令牌存入redis boolean result = this.saveTokenToRedis(authToken); if (!result){ //存入失败 ExceptionCast.cast(AuthCode.AUTH_LOGIN_TOKEN_SAVEFAIL); } return authToken; } //存入redis private boolean saveTokenToRedis(AuthToken authToken) { String key = "user_token:"+authToken.getJti(); String tokenString = JSON.toJSONString(authToken); stringRedisTemplate.boundValueOps(key).set(tokenString,tokenValiditySeconds, TimeUnit.SECONDS); Long expire = stringRedisTemplate.getExpire(key); return expire>0; } //申请令牌 private AuthToken applyToken(String username, String password, String clientId, String clientSecret) { ServiceInstance serviceInstance = loadBalancerClient.choose(XcServiceList.XC_SERVICE_UCENTER_AUTH); URI uri = serviceInstance.getUri(); String url = uri+"/auth/oauth/token"; MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); body.add("grant_type","password"); body.add("username",username); body.add("password",password); MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); headers.add("Authorization",this.getHttpBasic(clientId,clientSecret)); HttpEntity<MultiValueMap<String,String>> requestEntity = new HttpEntity<>(body,headers); restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){ @Override public void handleError(ClientHttpResponse response) throws IOException { if (response.getRawStatusCode() != 400 && response.getRawStatusCode() != 401){ super.handleError(response); } } }); ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class); Map map = responseEntity.getBody(); if (map == null || map.get("access_token")==null || map.get("refresh_token")==null || map.get("jti")==null){ ExceptionCast.cast(AuthCode.AUTH_LOGIN_APPLYTOKEN_FAIL); } AuthToken authToken = new AuthToken(); authToken.setAccess_token((String) map.get("access_token")); authToken.setRefresh_token((String) map.get("refresh_token")); authToken.setJti((String) map.get("jti")); return authToken; } private String getHttpBasic(String clientId, String clientSecret) { String value = clientId+":"+clientSecret; byte[] encode = Base64Utils.encode(value.getBytes()); return "Basic "+new String(encode); } public AuthToken getTokenFormRedis(String jti) { String key="user_token:"+jti; String tokenString = stringRedisTemplate.boundValueOps(key).get(); AuthToken authToken = JSON.parseObject(tokenString, AuthToken.class); return authToken; } public void delTokenFromRedis(String jti) { String key="user_token:"+jti; stringRedisTemplate.delete(key); } }
userjwt用户信息融到令牌中
import lombok.Data; import lombok.ToString; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import java.util.Collection; @Data @ToString public class UserJwt extends User { private String id; private String name; private String userpic; private String utype; private String companyId; public UserJwt(String username, String password, Collection<? extends GrantedAuthority> authorities) { super(username, password, authorities); } }
yml配置
1访问路径,redis信息
2auth设置redis过时时间==session过时时间(过时从新登陆用)
3私钥位置
4cookie域名(适配到不一样域中)和maxage
server: port: ${PORT:40400} servlet: context-path: /auth spring: application: name: xc-service-ucenter-auth redis: host: ${REDIS_HOST:127.0.0.1} port: ${REDIS_PORT:6379} timeout: 5000 #链接超时 毫秒 jedis: pool: maxActive: 3 maxIdle: 3 minIdle: 1 maxWait: -1 #链接池最大等行时间 -1没有限制 datasource: druid: url: ${MYSQL_URL:jdbc:mysql://localhost:3306/xc_user?characterEncoding=utf-8} username: root password: root driverClassName: com.mysql.jdbc.Driver initialSize: 5 #初始创建链接数量 minIdle: 5 #最小链接数量 maxActive: 20 #最大链接数量 maxWait: 10000 #获取链接最大等待时间,毫秒 testOnBorrow: true #申请链接时检测链接是否有效 testOnReturn: false #归还链接时检测链接是否有效 timeBetweenEvictionRunsMillis: 60000 #配置间隔检测链接是否有效的时间(单位是毫秒) minEvictableIdleTimeMillis: 300000 #链接在链接池的最小生存时间(毫秒) auth: tokenValiditySeconds: 1200 #token存储到redis的过时时间 clientId: XcWebApp clientSecret: XcWebApp cookieDomain: xuecheng.com cookieMaxAge: -1 encrypt: key-store: location: classpath:/xc.keystore secret: xuechengkeystore alias: xckey password: xuecheng eureka: client: registerWithEureka: true #服务注册开关 fetchRegistry: true #服务发现开关 serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址,多个中间用逗号分隔 defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/,http://localhost:50102/eureka/} instance: prefer-ip-address: true #将本身的ip地址注册到Eureka服务中 ip-address: ${IP_ADDRESS:127.0.0.1} instance-id: ${spring.application.name}:${server.port} #指定实例id ribbon: MaxAutoRetries: 2 #最大重试次数,当Eureka中能够找到服务,可是服务连不上时将会重试,若是eureka中找不到服务则直接走断路器 MaxAutoRetriesNextServer: 3 #切换实例的重试次数 OkToRetryOnAllOperations: false #对全部操做请求都进行重试,若是是get则能够,若是是post,put等操做没有实现幂等的状况下是很危险的,因此设置为false ConnectTimeout: 5000 #请求链接的超时时间 ReadTimeout: 6000 #请求处理的超时时间