springcloud gateway集成oauth2.0

直接进入主题

spring cloud gateway 简介

This project provides a library for building an API Gateway on top of Spring MVC. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency

springcloud gateway 官方文档 https://spring.io/projects/spring-cloud-gateway#overview

oauth的认证权限可以参考https://blog.csdn.net/a15835774652/article/details/107065563  传送门

常见的网关认证模式

1.网关充当资源服务器 同时转发相关的认证请求到认证服务器 用户请求不同的资源 在网关层验证,判断权限等操作;

2.网关只负责转发操作 进行验证在每个资源服务上 

这里采用第二种网关认证方式 

源码位置: https://github.com/passliang/tiger

项目整体结构如下 

auth-server 作为认证中心 

gateway 作为网关 负责转发相关操作  仅仅作为网关

一.首先搭建注册中心

tiger 父工程 pom 如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.style</groupId>
    <artifactId>tiger</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>tiger</name>
    <description>oauth2.0</description>

    <modules>
        <module>auth-server</module>
        <module>gateway</module>
        <module>registry</module>
        <module>user</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR8</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>

    </dependencyManagement>
</project>

注册中心 pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.style</groupId>
        <artifactId>tiger</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>registry</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>registry</name>
    <description>registry</description>

    <dependencies>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.yaml 配置

server:
  port: 20020

spring:
  application:
    name: regisry

eureka:
  client:
    ### 取消Eureka服务器自我注册
    registerWithEureka: false
    ### 注册中心的服务器,没有必要再去检索服务
    fetchRegistry: false
  instance:
    hostname: localhost
  server:
    waitTimeInMsWhenSyncEmpty: 0
    #关闭自我保护
    enableSelfPreservation: false
    #剔除时间间隔,单位:毫秒
    evictionIntervalTimerInMs: 4000

3.启动配置文件

@SpringBootApplication
@EnableEurekaServer
public class RegistryApplication {

   public static void main(String[] args) {
      SpringApplication.run(RegistryApplication.class, args);
   }

}

二.网关 

使用springcloud的gateway

1.pom文件如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.style</groupId>
        <artifactId>tiger</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>gateway</artifactId>
    <version>1.0.0</version>
    <name>gateway</name>
    <description>gateway</description>

    <dependencies>
        <!-- eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- zookeeper-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        <!-- consul-discovery-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- security-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

        <!-- actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator</artifactId>
        </dependency>

        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.yaml配置文件

bootstrap.yaml

server:
  port: 20060

spring:
  application:
    name: gateway
  cloud:
    zookeeper:
      # zookeeper 服务发现与注册失效(默认)
      enabled: false
    consul:
      # consul 服务发现与注册失效(默认)
      enabled: false

  profiles:
    #切换不同 环境 使用zookeeper 或者consul
    active: eureka



eureka:
  client:
    # Eureka 服务发现与注册失效(默认)
    enabled: false

--- # Profile For Eureka
spring:
  profiles: eureka
eureka:
  server: # 官方不存在的配置(自定义配置)
    host: 127.0.0.1
    port: 20020
  client:
    service-url:
      #注册中心地址
      #多注册中心
#      defaultZone: http://localhost:20021/eureka,http://localhost:20022/eureka,http://localhost:20023/eureka
      defaultZone: http://localhost:20020/eureka
    # 5 秒轮训一次
    registryFetchIntervalSeconds: 5
    enabled: true
  instance:
    # eureka client发送心跳给server端后,续约到期时间(默认90秒)
    leaseExpirationDurationInSeconds: 10
    #发送心跳续约间 5秒 发一次 心跳
    leaseRenewalIntervalInSeconds: 5
    metadata-map:
      instanceId: ${spring.application.name}:${server.port}


--- #zookeeper
spring:
  profiles: zookeeper
  cloud:
    zookeeper:
      connectString: localhost:2181
      enabled: true


--- #consul
spring:
  profiles: consul
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        #是否需要注册
        register: true
        #注册的实例ID (唯一标志)
        instance-id: ${spring.application.name}:${server.port}
        #服务的名称
        service-name: ${spring.application.name}
        #服务的请求端口
        port: ${server.port}
        #指定开启ip地址注册
        prefer-ip-address: true
        #当前服务的请求ip
        ip-address: 127.0.0.1
        enabled: true



application.yaml
spring:
  application:
    name: gateway
  autoconfigure:
    exclude: org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration

  cloud:
    gateway:
      routes:
        - id : oauth
          uri: lb://AUTH-SERVER
          predicates:
            - Path=/oauth/*
        - id: user
          uri: lb://USER
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix=1


#默认暴露所有的节点给 adminServer 生产上谨慎使用 可增加认证
management:
  endpoints:
    web:
      exposure:
        #暴露hystrix监控端点 hystrix.stream
        include: '*'
  endpoint:
    health:
      show-details: always

3.启动类

@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

   public static void main(String[] args) {
      SpringApplication.run(GatewayApplication.class, args);
   }

}

4. 安全的配置 (这个配置是必须加的 过滤到csrf)

gateway是用的webflux 和javax包下filter会冲突  注解这里使用 EnableWebFluxSecurity

WebSecurityConfig
@EnableWebFluxSecurity
@Configuration
public class WebSecurityConfig {

   @Bean
   public SecurityWebFilterChain webFluxFilterChain(ServerHttpSecurity http) {
      http
         .csrf().disable()
         .authorizeExchange()
         .pathMatchers("/**").permitAll()
         //option 请求默认放行
         .pathMatchers(HttpMethod.OPTIONS).permitAll()
         .and()
         .formLogin()
      ;

      return http.build();
   }

}

三.认证中心

pom依赖如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.style</groupId>
        <artifactId>tiger</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>auth-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>auth-server</name>
    <description>auth-server</description>

    <dependencies>
        <!-- eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- zookeeper-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        <!-- consul-discovery-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- security-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <!-- oauth2-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <!--  web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator</artifactId>
        </dependency>
        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.yaml配置

bootstrap.yaml

server:
  port: 20110

spring:
  application:
    name: auth-server
  cloud:
    zookeeper:
      # zookeeper 服务发现与注册失效(默认)
      enabled: false
    consul:
      # consul 服务发现与注册失效(默认)
      enabled: false

  profiles:
    #切换不同 环境 使用zookeeper 或者consul
    active: eureka



eureka:
  client:
    # Eureka 服务发现与注册失效(默认)
    enabled: false

--- # Profile For Eureka
spring:
  profiles: eureka
eureka:
  server: # 官方不存在的配置(自定义配置)
    host: 127.0.0.1
    port: 20020
  client:
    service-url:
      #注册中心地址
      defaultZone: http://localhost:20020/eureka
    #多注册中心
#      defaultZone: http://localhost:20021/eureka,http://localhost:20022/eureka,http://localhost:20023/eureka
    # 5 秒轮训一次
    registryFetchIntervalSeconds: 5
    enabled: true
  instance:
    # eureka client发送心跳给server端后,续约到期时间(默认90秒)
    leaseExpirationDurationInSeconds: 10
    #发送心跳续约间 5秒 发一次 心跳
    leaseRenewalIntervalInSeconds: 5
    metadata-map:
      instanceId: ${spring.application.name}:${server.port}


--- #zookeeper
spring:
  profiles: zookeeper
  cloud:
    zookeeper:
      connectString: localhost:2181
      enabled: true


--- #consul
spring:
  profiles: consul
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        #是否需要注册
        register: true
        #注册的实例ID (唯一标志)
        instance-id: ${spring.application.name}:${server.port}
        #服务的名称
        service-name: ${spring.application.name}
        #服务的请求端口
        port: ${server.port}
        #指定开启ip地址注册
        prefer-ip-address: true
        #当前服务的请求ip
        ip-address: 127.0.0.1
        enabled: true


application.yml
spring:
  application:
    name: auth-server
  autoconfigure:
    exclude: org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration



#默认暴露所有的节点给 adminServer 生产上谨慎使用 可增加认证
management:
  endpoints:
    web:
      exposure:
        #暴露hystrix监控端点 hystrix.stream
        include: '*'
  endpoint:
    health:
      show-details: always

3.启动类配置

@SpringBootApplication
@EnableDiscoveryClient
public class AuthServerApplication {

   public static void main(String[] args) {
      SpringApplication.run(AuthServerApplication.class, args);
   }

}

目录结构如上

AuthorizationServerConfig

客户端信息存于内存中

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

   @Autowired
   private AuthenticationManager authenticationManager;
   @Autowired
   private ClientDetailsService clientDetailsService;
   @Autowired
   private TokenStore tokenStore;
   @Autowired
   private JwtAccessTokenConverter jwtAccessTokenConverter;

   @Override
   public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
      endpoints
            //允许token请求调用的请求类型
            .allowedTokenEndpointRequestMethods(HttpMethod.POST, HttpMethod.GET)
            //认证管理器
            .authenticationManager(authenticationManager)
            //token
            .tokenServices(tokenServices())
            //认证码
            .authorizationCodeServices(authorizationCodeServices())
      ;
   }

   @Bean
   public AuthorizationServerTokenServices tokenServices() {
      DefaultTokenServices tokenServices = new DefaultTokenServices();
      //认证管理器
      tokenServices.setAuthenticationManager(authenticationManager);
      //客户端信息
      tokenServices.setClientDetailsService(clientDetailsService);
      //jwt token存储
      tokenServices.setTokenStore(tokenStore);
      //token增强
      TokenEnhancerChain tokenEnhancer = new TokenEnhancerChain();
      tokenEnhancer.setTokenEnhancers(Collections.singletonList(jwtAccessTokenConverter));
      tokenServices.setTokenEnhancer(tokenEnhancer);
      //支持刷新token
      tokenServices.setSupportRefreshToken(true);
      //token 有效期 2小时
      tokenServices.setAccessTokenValiditySeconds(2 * 60 * 60);
      // 刷新token有效期 7天
      tokenServices.setRefreshTokenValiditySeconds(7 * 24 * 60 * 60);
      return tokenServices;
   }

   /**
    * 授权码 这里使用内存存储
    *
    * @return AuthorizationCodeServices
    */
   @Bean
   public AuthorizationCodeServices authorizationCodeServices() {
      return new InMemoryAuthorizationCodeServices();
   }

   /**
    * 自定义 加密器
    *
    * @return PasswordEncoder
    */
   @Bean
   public PasswordEncoder passwordEncoder() {
      return new BCryptPasswordEncoder();
   }

   /**
    * 客户端的信息
    *
    * @param clients clients
    * @throws  Exception
    */
   @Override
   public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
      //配置内存中的 client
      clients.inMemory()
            .withClient("admin")
            .secret(new BCryptPasswordEncoder().encode("MyStyle"))
            //客户端允许的授权模式
            .authorities("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
            //允许的授权范围
            .scopes("all","read","write")
            //验证回调地址
            .redirectUris("https://www.baidu.com")
            .and()
            .withClient("user")
            .secret(new BCryptPasswordEncoder().encode("MyStyle"))
            //客户端允许的授权模式
            .authorities("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
            //允许的授权范围
            .scopes("read")
            //验证回调地址
            .redirectUris("https://www.baidu.com")
            .and()
            .build();
   }

   @Override
   public void configure(AuthorizationServerSecurityConfigurer security) {
      security
            //oauth/token_key是公开
            .tokenKeyAccess("permitAll()")
            //oauth/check_token公开
            .checkTokenAccess("permitAll()")
            //表单认证(申请令牌)
            .allowFormAuthenticationForClients()
      ;
   }

}
SecurityConfig

定义了两个用户都存于内存中 

package com.style.auth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;


/**
 * @author leon
 * @date 2020-09-21 13:45:17
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http
         .csrf().disable()
         .authorizeRequests()
         .antMatchers("/oauth/**").permitAll()
         .anyRequest().authenticated();
      ;
   }

   @Bean
   @Override
   public AuthenticationManager authenticationManager() throws Exception {
      return super.authenticationManager();
   }

   @Bean
   @Override
   public UserDetailsService userDetailsService() {
      //内存模式下创建的用户
      //权限列表
      UserDetails admin = User.withUsername("admin")
            .password(new BCryptPasswordEncoder().encode("123456"))
            //角色
            .roles("ADMIN", "DEVELOPER")
            //权限
            .authorities("get","update")
            .build();

      //开发者
      UserDetails developer = User.withUsername("developer")
            .password(new BCryptPasswordEncoder().encode("123456"))
            //角色
            .roles("DEVELOPER")
            //权限
            .authorities("get")
            .build();


      InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
      userDetailsManager.createUser(admin);
      userDetailsManager.createUser(developer);
      return userDetailsManager;
   }

}

token配置

TokenConfig

@Configuration
public class TokenConfig {

   private static final String SIGN_KEY = "MyStyle";

   /**
    * jwt token 存储
    *
    * @return TokenStore
    */
   @Bean
   public TokenStore tokenStore() {
      return new JwtTokenStore(jwtAccessTokenConverter());
   }

   /**
    * jwt tokenConvert
    *
    * @return JwtAccessTokenConverter
    */
   @Bean
   public JwtAccessTokenConverter jwtAccessTokenConverter() {
      JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
      jwtAccessTokenConverter.setSigningKey(SIGN_KEY);
      return jwtAccessTokenConverter;
   }

}

四.用户中心

用户中心作为资源服务器 校验token以及权限

1.pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.style</groupId>
        <artifactId>tiger</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>user</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>user</name>
    <description>user</description>

    <dependencies>
        <!-- eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- zookeeper-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        <!-- consul-discovery-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <!-- security-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>
        <!-- oauth2-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
        <!-- actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-actuator</artifactId>
        </dependency>
        <!-- web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.yaml配置文件

bootstrap.yaml

server:
  port: 20080

spring:
  application:
    name: user
  cloud:
    zookeeper:
      # zookeeper 服务发现与注册失效(默认)
      enabled: false
    consul:
      # consul 服务发现与注册失效(默认)
      enabled: false

  profiles:
    #切换不同 环境 使用zookeeper 或者consul
    active: eureka

eureka:
  client:
    # Eureka 服务发现与注册失效(默认)
    enabled: false

--- # Profile For Eureka
spring:
  profiles: eureka
eureka:
  server: # 官方不存在的配置(自定义配置)
    host: 127.0.0.1
    port: 20020
  client:
    service-url:
      #注册中心地址
      #多注册中心
#      defaultZone: http://localhost:20021/eureka,http://localhost:20022/eureka,http://localhost:20023/eureka
      defaultZone: http://localhost:20020/eureka
    # 5 秒轮训一次
    registryFetchIntervalSeconds: 5
    enabled: true
  instance:
    # eureka client发送心跳给server端后,续约到期时间(默认90秒)
    leaseExpirationDurationInSeconds: 10
    #发送心跳续约间 5秒 发一次 心跳
    leaseRenewalIntervalInSeconds: 5
    metadata-map:
      instanceId: ${spring.application.name}:${server.port}


--- #zookeeper
spring:
  profiles: zookeeper
  cloud:
    zookeeper:
      connectString: localhost:2181
      enabled: true


--- #consul
spring:
  profiles: consul
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        #是否需要注册
        register: true
        #注册的实例ID (唯一标志)
        instance-id: ${spring.application.name}:${server.port}
        #服务的名称
        service-name: ${spring.application.name}
        #服务的请求端口
        port: ${server.port}
        #指定开启ip地址注册
        prefer-ip-address: true
        #当前服务的请求ip
        ip-address: 127.0.0.1
        enabled: true

application.yaml


spring:
  application:
    name: user
  autoconfigure:
    exclude: org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration




#默认暴露所有的节点给 adminServer 生产上谨慎使用 可增加认证
management:
  endpoints:
    web:
      exposure:
        #暴露hystrix监控端点 hystrix.stream
        include: '*'
  endpoint:
    health:
      show-details: always

整体结构

3.启动文件

@SpringBootApplication
@EnableDiscoveryClient
public class UserApplication {

   public static void main(String[] args) {
      SpringApplication.run(UserApplication.class, args);
   }

}

4. 资源服务配置

ResourceServerConfig
@EnableResourceServer
@Configuration
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

   public static final String RESOURCE_ID = "resource";

   @Autowired
   private TokenStore tokenStore;

   @Override
   public void configure(ResourceServerSecurityConfigurer resources) {
      resources
            .resourceId(RESOURCE_ID)
            .tokenStore(tokenStore)
            .stateless(true)
      ;
   }

   @Override
   public void configure(HttpSecurity http) throws Exception {
      http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/update").access("hasAuthority('update')")
            .antMatchers("/get").access("hasAuthority('get')")
            .antMatchers("/info").permitAll()
            .anyRequest().authenticated();
   }

}
WebSecurityConfig
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable()
            .authorizeRequests()
            .anyRequest().authenticated();

   }

}
TokenConfig
@Configuration
public class TokenConfig {

   private static final String VERIFY_KEY = "MyStyle";

   @Bean
   public TokenStore tokenStore() {
      return new JwtTokenStore(jwtAccessTokenConverter());
   }

   @Bean
   public JwtAccessTokenConverter jwtAccessTokenConverter() {
      JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
      jwtAccessTokenConverter.setVerifierKey(VERIFY_KEY);
      jwtAccessTokenConverter.setSigningKey(VERIFY_KEY);
      return jwtAccessTokenConverter;
   }
}
AuthController

验证的测试接口

@RestController
public class AuthController {

   @GetMapping("/get")
   public String get() {
      return "获取接口";
   }

   @PostMapping("/update")
   public String update() {
      return "更新接口";
   }

   @GetMapping("/info")
   public String info() {
      return "详情 自由查看 不受限制";
   }
}

update 接口需要有update 权限  get 接口需要有 get权限

项目到此搭建完成

首先启动注册中心 在启动网关 认证中心 用户中心

通过网关访问 user/get

返回未正常 该接口是需要添加token 才可以访问

通过网关获取一个token

http://localhost:20060/oauth/token?client_id=admin&client_secret=MyStyle&grant_type=password&username=developer&password=123456

获取token成功 

在拿着token 去调用 /user/get

调用成功

在尝试调用下 /user/update

访问被拒绝

update 接口需要 update 权限

再次调用获取token接口 这次使用admin 用户

用新的token 去调用 /user/update

调用成功

再来测试下 /user/info

不携带token进行请求

成功

到此结束

祝大家国庆快乐!!! 

猜你喜欢

转载自blog.csdn.net/a15835774652/article/details/108833327