SpringCloud+OAuth2+Spring Security+Redis+Jwt+Gateway/zuul實現的微服務統一認證授權

轉載請表明出處 https://blog.csdn.net/Amor_Leo/article/details/101751690 謝謝

源碼

代碼太多了,貼的不完整 ,可以看我上傳到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了)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章