收款定制开发Gateway + Oauth2实现单点登录

首先引入pom依赖

1、resilience 熔断器
2、gateway 网关
3、eureka client 收款定制开发服务注册中心
4、lombok插件
5、actuator状态监控

  1. <dependencies>
  2. <!-- 熔断器-->
  3. <dependency>
  4. <groupId>io.github.resilience4j</groupId>
  5. <artifactId>resilience4j-feign</artifactId>
  6. <version>1.1.0</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>org.springframework.boot</groupId>
  10. <artifactId>spring-boot-starter</artifactId>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.springframework.boot</groupId>
  14. <artifactId>spring-boot-starter-test</artifactId>
  15. <scope>test</scope>
  16. </dependency>
  17. <!-- Gateway -->
  18. <dependency>
  19. <groupId>org.springframework.cloud</groupId>
  20. <artifactId>spring-cloud-starter-gateway</artifactId>
  21. </dependency>
  22. <!-- 注册中心 -->
  23. <dependency>
  24. <groupId>org.springframework.cloud</groupId>
  25. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  26. <version>2.2.2.RELEASE</version>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.projectlombok</groupId>
  30. <artifactId>lombok</artifactId>
  31. <optional>true</optional>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-actuator</artifactId>
  36. </dependency>
  37. </dependencies>

application.yml配置

1、gateway信息
2、actuator状态信息
3、配置eureka server收款定制开发地址及注册信息
4、日志配置
5、获取oauth2的jwt key

  1. server:
  2.   port: 18890
  3. spring:
  4.   application:
  5.     name: open-api-gateway
  6.   profiles:
  7.     active: local
  8.   cloud:
  9.     gateway:
  10.       discovery:
  11.         locator:
  12.           enabled: true
  13.           lower-case-service-id: true
  14.       globalcors:
  15.         corsConfigurations:
  16.           '[/**]':
  17.             allowedOrigins: "*"
  18.             allowedMethods: "*"
  19.       default-filters:
  20.         - AddRequestParameter=gateway_type, member
  21.         - AddRequestHeader=gateway_type, member
  22. management:
  23.   endpoints:
  24.     web:
  25.       exposure:
  26.         include: "*"
  27.   endpoint:
  28.     health:
  29.       show-details: always
  30.        
  31. eureka:
  32.   instance:
  33.     prefer-ip-address: true
  34.     instance-id: ${spring.cloud.client.ip-address}:${server.port}
  35.   client:
  36.     service-url:
  37.       defaultZone: http://127.0.0.1:22001/eureka
  38. logging:
  39.   level:
  40.     com.dq.edu: debug
  41.     com:
  42.       netflix:
  43.         discovery: error
  44. spring:
  45.   security:
  46.     oauth2:
  47.       resourceserver:
  48.         jwt:
  49.           jwk-set-uri: http://127.0.0.1:18889/auth-server/private/jwk_public_key

核心内容:security配置、PermissionFilter收款定制开发鉴权过滤器

1、security配置

  1. package com.digquant.openapigateway.config;
  2.  
  3. import com.digquant.openapigateway.entity.Response;
  4. import lombok.AllArgsConstructor;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.core.io.buffer.DataBuffer;
  9. import org.springframework.core.io.buffer.DataBufferFactory;
  10. import org.springframework.core.io.buffer.DataBufferUtils;
  11. import org.springframework.http.HttpMethod;
  12. import org.springframework.http.MediaType;
  13. import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
  14. import org.springframework.security.config.web.server.ServerHttpSecurity;
  15. import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder;
  16. import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
  17. import org.springframework.security.web.server.SecurityWebFilterChain;
  18. import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
  19. import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
  20. import org.springframework.util.StringUtils;
  21. import org.springframework.web.server.ServerWebExchange;
  22. import reactor.core.publisher.Mono;
  23.  
  24. import java.nio.charset.Charset;
  25.  
  26. @Slf4j
  27. @Configuration
  28. @AllArgsConstructor
  29. @EnableWebFluxSecurity
  30. public class SecurityConfig {
  31.  
  32.     private final ReactiveJwtDecoder jwtDecoder;
  33.  
  34.     @Bean
  35.     public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  36.         http.cors().disable().csrf().disable();
  37.         http
  38.                 .authorizeExchange()
  39.                 .pathMatchers("/**").permitAll()
  40.                 .pathMatchers("/**/public/**").permitAll()
  41.                 .pathMatchers("/**/static/**").permitAll()
  42.                 .pathMatchers("/*/oauth/**").permitAll()
  43.                 .pathMatchers("/actuator/**").permitAll()
  44.                 .pathMatchers(HttpMethod.OPTIONS).permitAll()
  45.                 .anyExchange().authenticated()
  46.                 .and()
  47.                 .exceptionHandling()
  48.                 .accessDeniedHandler(serverAccessDeniedHandler())
  49.                 .authenticationEntryPoint(serverAuthenticationEntryPoint())
  50.                 .and()
  51.                 .oauth2ResourceServer()
  52.                 .jwt()
  53.                 .jwtDecoder(jwtDecoder)
  54.                 .and()
  55.                 .bearerTokenConverter(new ServerBearerTokenAuthenticationConverter());
  56.         return http.build();
  57.     }
  58.  
  59.     @Bean
  60.     public ServerAccessDeniedHandler serverAccessDeniedHandler() {
  61.         return (exchange, denied) -> {
  62.             log.debug("没有权限");
  63.             String errMsg = StringUtils.hasText(denied.getMessage()) ? denied.getMessage() : "没有权限";
  64.             Response result = new Response(1, errMsg);
  65.             return create(exchange, result);
  66.         };
  67.     }
  68.  
  69.     @Bean
  70.     public ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
  71.         return (exchange, e) -> {
  72.             log.debug("认证失败");
  73.             String errMsg = StringUtils.hasText(e.getMessage()) ? e.getMessage() : "认证失败";
  74.             Response result = new Response(1, errMsg);
  75.             return create(exchange, result);
  76.         };
  77.     }
  78.  
  79.     private Mono<Void> create(ServerWebExchange exchange, Response result) {
  80.         return Mono.defer(() -> Mono.just(exchange.getResponse()))
  81.                 .flatMap(response -> {
  82.                     response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
  83.                     DataBufferFactory dataBufferFactory = response.bufferFactory();
  84.                     DataBuffer buffer = dataBufferFactory.wrap(createErrorMsg(result));
  85.                     return response.writeWith(Mono.just(buffer))
  86.                             .doOnError(error -> DataBufferUtils.release(buffer));
  87.                 });
  88.     }
  89.  
  90.     private byte[] createErrorMsg(Response result) {
  91.         return result.getErrMsg().getBytes(Charset.defaultCharset());
  92.     }
  93. }

gateway是基于 WebFlux的响应式编程框架,所以在使用securityConfig时采用的注解是@EnableWebFluxSecurity

2、PermissionFilter

  1. package com.digquant.openapigateway.filter;
  2.  
  3. import com.digquant.openapigateway.utils.IStrings;
  4. import lombok.AllArgsConstructor;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.core.annotation.Order;
  7. import org.springframework.http.HttpHeaders;
  8. import org.springframework.http.server.reactive.ServerHttpRequest;
  9. import org.springframework.security.core.context.ReactiveSecurityContextHolder;
  10. import org.springframework.security.core.context.SecurityContext;
  11. import org.springframework.security.oauth2.jwt.Jwt;
  12. import org.springframework.security.oauth2.server.resource.authentication.AbstractOAuth2TokenAuthenticationToken;
  13. import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
  14. import org.springframework.stereotype.Component;
  15. import org.springframework.web.server.ServerWebExchange;
  16. import org.springframework.web.server.WebFilter;
  17. import org.springframework.web.server.WebFilterChain;
  18. import reactor.core.publisher.Mono;
  19.  
  20. import java.util.Objects;
  21.  
  22. @Slf4j
  23. @Order
  24. @Component
  25. @AllArgsConstructor
  26. public class PermissionFilter implements WebFilter {
  27.  
  28.     @Override
  29.     public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
  30.         return ReactiveSecurityContextHolder.getContext()
  31.                 //排除没有Token的
  32.                 .filter(Objects::nonNull)
  33. //                //检查该路径是否需要权限
  34. //                .filter(var -> permissionStore.usingPermission(exchange.getRequest().getPath().value()))
  35.                 .map(SecurityContext::getAuthentication)
  36.                 .map(authentication -> (JwtAuthenticationToken) authentication)
  37.                 .doOnNext(jwtAuthenticationToken -> {
  38.                     String path = exchange.getRequest().getPath().value();
  39.                     log.info("请求 uri {}", path);
  40.                 })
  41.                 .map(AbstractOAuth2TokenAuthenticationToken::getPrincipal)
  42.                 .map(var -> (Jwt) var)
  43.                 .map(jwt -> {
  44.                     String tokenValue = jwt.getTokenValue();
  45.                     ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
  46.                     builder.header(HttpHeaders.AUTHORIZATION, IStrings.splice("Bearer ", tokenValue));
  47.                     ServerHttpRequest request = builder.build();
  48.                     return exchange.mutate().request(request).build();
  49.                 })
  50.                 .defaultIfEmpty(exchange)
  51.                 .flatMap(chain::filter);
  52.     }
  53. }

1、使用permissionStore来记录uri的权限要求
2、获取到jwtToken时,处理token所携带的权限,用于匹配是否能请求对应资源

1、eureka client
2、spring boot mvc
3、redis 用于存储jwt
4、mysql用于记录用户资源权限
5、oauth2组件
6、httpclient fregn用于用户登陆鉴权

  1. <dependencies>
  2.        <dependency>
  3.            <groupId>org.springframework.cloud</groupId>
  4.            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5.            <version>2.2.2.RELEASE</version>
  6.        </dependency>
  7.  
  8.        <dependency>
  9.            <groupId>org.springframework.boot</groupId>
  10.            <artifactId>spring-boot-starter-web</artifactId>
  11.        </dependency>
  12.  
  13.        <dependency>
  14.            <groupId>org.springframework.boot</groupId>
  15.            <artifactId>spring-boot-starter-data-redis</artifactId>
  16.        </dependency>
  17.  
  18.        <dependency>
  19.            <groupId>org.mybatis.spring.boot</groupId>
  20.            <artifactId>mybatis-spring-boot-starter</artifactId>
  21.            <version>2.1.1</version>
  22.        </dependency>
  23.       <dependency>
  24.            <groupId>com.alibaba</groupId>
  25.            <artifactId>druid</artifactId>
  26.            <version>1.1.21</version>
  27.        </dependency>
  28.  
  29.        <dependency>
  30.            <groupId>mysql</groupId>
  31.            <artifactId>mysql-connector-java</artifactId>
  32.            <version>8.0.18</version>
  33.        </dependency>
  34.  
  35.      <!-- oauth2-->
  36.        <dependency>
  37.            <groupId>org.springframework.cloud</groupId>
  38.            <artifactId>spring-cloud-starter-oauth2</artifactId>
  39.            <version>2.2.0.RELEASE</version>
  40.        </dependency>
  41.        <dependency>
  42.            <groupId>org.springframework.cloud</groupId>
  43.            <artifactId>spring-cloud-starter-security</artifactId>
  44.            <version>2.2.0.RELEASE</version>
  45.        </dependency>
  46.  
  47.        <dependency>
  48.            <groupId>org.springframework.security</groupId>
  49.            <artifactId>spring-security-oauth2-jose</artifactId>
  50.            <version>5.2.2.RELEASE</version>
  51.        </dependency>
  52. <!-- HttpClient -->
  53.        <dependency>
  54.            <groupId>org.springframework.cloud</groupId>
  55.            <artifactId>spring-cloud-starter-openfeign</artifactId>
  56.            <version>2.2.2.RELEASE</version>
  57.        </dependency>
  58.        <dependency>
  59.            <groupId>io.github.openfeign</groupId>
  60.            <artifactId>feign-okhttp</artifactId>
  61.            <version>10.9</version>
  62.        </dependency>
  63.  
  64.        <dependency>
  65.            <groupId>org.projectlombok</groupId>
  66.            <artifactId>lombok</artifactId>
  67.            <optional>true</optional>
  68.        </dependency>
  69.  
  70.    </dependencies>

应用配置

  1. server:
  2.   port: 37766
  3. spring:
  4.   application:
  5.     name: auth-server
  6.   mvc:
  7.     throw-exception-if-no-handler-found: true
  8.   profiles:
  9.     active: dev
  10.  
  11. mybatis:
  12.   mapper-locations: classpath:mapper/*.xml
  13.   type-aliases-package: com.digquant.enity.po
  14.  
  15.  
  16. logging:
  17.   level:
  18.     com:
  19.       digquant:
  20.         dao: info
  21.   file:
  22.     path: /dq/log/new/auth-server
  23.  
  24.  
  25. digquant:
  26.   authorization:
  27.     auth-jwt-jks: hq-jwt.jks
  28.     auth-jwt-key: hq-jwt
  29.     auth-jwt-password: hq940313
  30.     access-token-validity-seconds: 14400
  31.     refresh-token-validity-seconds: 86400

1、AuthorizationServerConfig配置

  1. package com.digquant.config;
  2.  
  3. import com.digquant.dao.CustomRedisTokenStore;
  4. import com.digquant.enity.JWTProperties;
  5. import com.digquant.enity.Response;
  6. import com.digquant.service.OAuthUserService;
  7. import lombok.AllArgsConstructor;
  8. import lombok.extern.slf4j.Slf4j;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.core.io.ClassPathResource;
  12. import org.springframework.data.redis.connection.RedisConnectionFactory;
  13. import org.springframework.http.HttpStatus;
  14. import org.springframework.http.MediaType;
  15. import org.springframework.http.ResponseEntity;
  16. import org.springframework.security.authentication.AuthenticationManager;
  17. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  18. import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
  19. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  20. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  21. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  22. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  23. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  24. import org.springframework.security.oauth2.provider.ClientDetailsService;
  25. import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
  26. import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
  27. import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
  28. import org.springframework.security.oauth2.provider.token.TokenStore;
  29. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  30. import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
  31. import org.springframework.security.web.AuthenticationEntryPoint;
  32. import org.springframework.security.web.access.AccessDeniedHandler;
  33.  
  34. import javax.servlet.http.HttpServletResponse;
  35. import javax.sql.DataSource;
  36. import java.io.IOException;
  37.  
  38.  
  39. @Slf4j
  40. @Configuration
  41. @AllArgsConstructor
  42. @EnableAuthorizationServer
  43. public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  44.  
  45.     private final JWTProperties jwtProperties;
  46.  
  47.     /**
  48.      * 注入权限验证控制器 支持 password grant type
  49.      */
  50.     private final AuthenticationManager authenticationManager;
  51.  
  52.     /**
  53.      * 数据源
  54.      */
  55.     private final DataSource dataSource;
  56.  
  57.     /**
  58.      * 开启refresh_token
  59.      */
  60.     private final OAuthUserService userService;
  61.  
  62.     /**
  63.      * 采用redis 存储token
  64.      */
  65.     private final RedisConnectionFactory redisConnectionFactory;
  66.  
  67.     @Override
  68.     public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  69.         security.allowFormAuthenticationForClients()
  70.                 .checkTokenAccess("permitAll()")
  71.                 .tokenKeyAccess("permitAll()")
  72.                 .authenticationEntryPoint(authenticationEntryPoint())
  73.                 .accessDeniedHandler(accessDeniedHandler());
  74.     }
  75.  
  76.     @Bean
  77.     public AccessDeniedHandler accessDeniedHandler() {
  78.         return (request, response, accessDeniedException) -> {
  79.             Response result = new Response(1, accessDeniedException.getMessage());
  80.             writerResponse(response, result, HttpStatus.FORBIDDEN.value());
  81.         };
  82.     }
  83.  
  84.     @Bean
  85.     public AuthenticationEntryPoint authenticationEntryPoint() {
  86.         return (request, response, authException) -> {
  87.             Response result = new Response(1, authException.getMessage());
  88.             writerResponse(response, result, HttpStatus.UNAUTHORIZED.value());
  89.         };
  90.     }
  91.  
  92.     private void writerResponse(HttpServletResponse response, Response result, int status) throws IOException {
  93.         response.setStatus(status);
  94.         response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
  95.         response.setCharacterEncoding("UTF-8");
  96.         response.getWriter().print(result.getErrMsg());
  97.         response.getWriter().flush();
  98.     }
  99.  
  100.     @Bean("redisTokenStore")
  101.     public TokenStore redisTokenStore() {
  102.         return new CustomRedisTokenStore(redisConnectionFactory);
  103.     }
  104.  
  105.     @Bean
  106.     public JwtAccessTokenConverter jwtAccessTokenConverter() {
  107.         JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
  108.         jwtAccessTokenConverter.setKeyPair(keyStoreKeyFactory().getKeyPair(jwtProperties.getAuthJwtKey()));
  109.         return jwtAccessTokenConverter;
  110.     }
  111.  
  112.     @Bean
  113.     public KeyStoreKeyFactory keyStoreKeyFactory() {
  114.         return new KeyStoreKeyFactory(new ClassPathResource(jwtProperties.getAuthJwtJks()), jwtProperties.getAuthJwtPassword().toCharArray());
  115.     }
  116.  
  117.     @Bean
  118.     public DefaultTokenServices tokenServices() {
  119.         DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
  120.         defaultTokenServices.setTokenStore(redisTokenStore());
  121.         defaultTokenServices.setTokenEnhancer(jwtAccessTokenConverter());
  122.         defaultTokenServices.setSupportRefreshToken(true);
  123.         defaultTokenServices.setReuseRefreshToken(false);
  124.         defaultTokenServices.setAccessTokenValiditySeconds(jwtProperties.getAccessTokenValiditySeconds());
  125.         defaultTokenServices.setRefreshTokenValiditySeconds(jwtProperties.getRefreshTokenValiditySeconds());
  126.         return defaultTokenServices;
  127.     }
  128.  
  129.     @Override
  130.     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  131.         //开启密码授权类型
  132.         endpoints
  133.                 .authenticationManager(authenticationManager)
  134.                 //配置token存储方式
  135.                 .tokenStore(redisTokenStore())
  136.                 //需要额外配置,用于refres_token
  137.                 .userDetailsService(userService)
  138.                 //
  139.                 .tokenServices(tokenServices())
  140.                 .accessTokenConverter(jwtAccessTokenConverter())
  141.                 .exceptionTranslator(exceptionTranslator());
  142.     }
  143.  
  144.     @Bean
  145.     public WebResponseExceptionTranslator exceptionTranslator() {
  146.         return exception -> {
  147.             return ResponseEntity.status(HttpStatus.OK).body(new OAuth2Exception(exception.getMessage()));
  148.         };
  149.     }
  150.  
  151.     @Bean
  152.     public ClientDetailsService clientDetails() {
  153.         return new JdbcClientDetailsService(dataSource);
  154.     }
  155.  
  156.     @Override
  157.     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  158. //        clients.withClientDetails(clientDetails());
  159.         clients.inMemory()
  160.                 .withClient("open_api")
  161.                 .authorizedGrantTypes("password","refresh_token")
  162.                 .authorities("USER")
  163.                 .scopes("read", "write")
  164.                 .resourceIds("auth-server")
  165.                 .secret(new BCryptPasswordEncoder().encode("digquant"));
  166.  
  167.     }
  168. }

2、ResourceServerConfig 资源服务配置

  1. package com.digquant.config;
  2.  
  3. import lombok.AllArgsConstructor;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.core.annotation.Order;
  6. import org.springframework.http.HttpMethod;
  7. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  8. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  9. import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  10. import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
  11. import org.springframework.security.web.AuthenticationEntryPoint;
  12. import org.springframework.security.web.access.AccessDeniedHandler;
  13.  
  14. @Order(6)
  15. @Configuration
  16. @AllArgsConstructor
  17. @EnableResourceServer
  18. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  19.     private final AccessDeniedHandler accessDeniedHandler;
  20.  
  21.     private final AuthenticationEntryPoint authenticationEntryPoint;
  22.  
  23.     @Override
  24.     public void configure(HttpSecurity http) throws Exception {
  25.         http.csrf().disable();
  26.         http
  27.                 .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
  28.                 .and().authorizeRequests()
  29.                 .antMatchers("/swagger-ui.html","/webjars/**").permitAll()
  30.                 .antMatchers("/oauth/**").permitAll()
  31.                 .antMatchers("/actuator/**").permitAll()
  32.                 .antMatchers("/").permitAll()
  33.                 .antMatchers(HttpMethod.OPTIONS).permitAll()
  34.                 .anyRequest().permitAll();
  35.     }
  36.  
  37.     @Override
  38.     public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  39.         resources.authenticationEntryPoint(authenticationEntryPoint)
  40.                 .accessDeniedHandler(accessDeniedHandler)
  41.                 .resourceId("auth-server");
  42.     }
  43. }

3、SecurityConfig配置

  1. package com.digquant.config;
  2.  
  3. import com.digquant.service.CustomAuthenticationProvider;
  4. import com.digquant.service.OAuthUserService;
  5. import lombok.AllArgsConstructor;
  6. import org.springframework.boot.autoconfigure.AutoConfigureAfter;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9. import org.springframework.core.annotation.Order;
  10. import org.springframework.http.HttpMethod;
  11. import org.springframework.security.authentication.AuthenticationManager;
  12. import org.springframework.security.authentication.AuthenticationProvider;
  13. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  14. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  15. import org.springframework.security.config.annotation.web.builders.WebSecurity;
  16. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  17. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  18. import org.springframework.security.config.http.SessionCreationPolicy;
  19. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  20. import org.springframework.security.crypto.password.PasswordEncoder;
  21.  
  22. @Order(7)
  23. @Configuration
  24. @EnableWebSecurity
  25. @AllArgsConstructor
  26. @AutoConfigureAfter(ResourceServerConfig.class)
  27. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  28.  
  29.     private final OAuthUserService userService;
  30.  
  31.     @Override
  32.     protected void configure(HttpSecurity http) throws Exception {
  33.         http.cors().and().csrf().disable();
  34.         http.authorizeRequests()
  35.                 .antMatchers("/oauth/**").permitAll()
  36.                 .antMatchers("/public/**").permitAll()
  37.                 .antMatchers("/actuator/**").permitAll()
  38.                 .antMatchers("/private/**").permitAll()
  39.                 .antMatchers("/").permitAll()
  40.                 .antMatchers(HttpMethod.OPTIONS).permitAll()
  41.                 .anyRequest().permitAll()
  42.                 .and()
  43.                 .sessionManagement()
  44.                 .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  45.     }
  46.  
  47.     @Override
  48.     public void configure(WebSecurity web) throws Exception {
  49.         web.ignoring().antMatchers("/favor.ico");
  50.     }
  51.  
  52.     @Bean
  53.     @Override
  54.     public AuthenticationManager authenticationManagerBean() throws Exception {
  55.         return super.authenticationManagerBean();
  56.     }
  57.  
  58.     @Override
  59.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  60.         auth.authenticationProvider(authenticationProvider());
  61.     }
  62.  
  63.     @Bean
  64.     public PasswordEncoder passwordEncoder() {
  65.         return new BCryptPasswordEncoder();
  66.     }
  67.  
  68.     @Bean
  69.     public AuthenticationProvider authenticationProvider() {
  70.         CustomAuthenticationProvider provider = new CustomAuthenticationProvider()
  71.                 .setUserDetailsService(userService)
  72.                 .setPasswordEncoder(passwordEncoder());
  73.         provider.setHideUserNotFoundExceptions(false);
  74.         return provider;
  75.     }
  76.  
  77. }

4、JwkController 用于gateway 请求jwt私钥

  1. package com.digquant.controller;
  2.  
  3. import com.digquant.enity.JWTProperties;
  4. import com.nimbusds.jose.jwk.JWKSet;
  5. import com.nimbusds.jose.jwk.RSAKey;
  6. import io.swagger.annotations.Api;
  7. import io.swagger.annotations.ApiOperation;
  8. import lombok.AllArgsConstructor;
  9. import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
  10. import org.springframework.web.bind.annotation.*;
  11.  
  12. import java.security.interfaces.RSAPublicKey;
  13. import java.util.Map;
  14.  
  15. @Api(tags = "jwk")
  16. @RestController
  17. @RequestMapping("/private")
  18. @AllArgsConstructor
  19. public class JwkController {
  20.     private final KeyStoreKeyFactory keyStoreKeyFactory;
  21.  
  22.     private final JWTProperties jwtProperties;
  23.  
  24.     @ApiOperation("获取jwk")
  25.     @PostMapping("/jwk_public_key")
  26.     public Map<String, Object> getKey() {
  27.         RSAPublicKey publicKey = (RSAPublicKey) keyStoreKeyFactory.getKeyPair(jwtProperties.getAuthJwtKey()).getPublic();
  28.         RSAKey key = new RSAKey.Builder(publicKey).build();
  29.         return new JWKSet(key).toJSONObject();
  30.     }
  31.  
  32. }

5、用户鉴权服务,获取用户信息

  1. package com.digquant.service;
  2.  
  3. import com.digquant.enity.to.AuthenticationTO;
  4. import com.digquant.enums.LoginType;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8. import org.springframework.security.core.userdetails.UserDetails;
  9. import org.springframework.security.core.userdetails.UserDetailsService;
  10. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  11. import org.springframework.stereotype.Component;
  12. import org.springframework.util.CollectionUtils;
  13.  
  14. import java.util.List;
  15. import java.util.Map;
  16.  
  17. @Slf4j
  18. @Component
  19. public class OAuthUserService implements UserDetailsService {
  20.  
  21.     @Autowired(required = false)
  22.     private List<OAuthUserProcessor> oAuthUserProcessors;
  23.  
  24.     public UserDetails loadUser(String username, UsernamePasswordAuthenticationToken authentication) {
  25.         AuthenticationTO authenticationTO = new AuthenticationTO();
  26.         authenticationTO.setUsername(username);
  27.         authenticationTO.setPassword((String) authentication.getCredentials());
  28.  
  29.         Map map = (Map) authentication.getDetails();
  30.         String scope = (String) map.get("scope");
  31.         String grantType = (String) map.get("grant_type");
  32.         String clientId = (String) map.get("client_id");
  33.  
  34.         authenticationTO.setScope(scope);
  35.         authenticationTO.setGrantType(grantType);
  36.         authenticationTO.setLoginType(LoginType.PASSWORD);
  37.         authenticationTO.setClientId(clientId);
  38.  
  39.         if (log.isDebugEnabled()) {
  40.             log.debug("请求认证参数:{}", authenticationTO);
  41.         }
  42.         if (!CollectionUtils.isEmpty(oAuthUserProcessors)) {
  43.             //目前只支持客户端密码登录方式
  44.             for (OAuthUserProcessor oAuthUserProcessor : oAuthUserProcessors) {
  45.                 if (oAuthUserProcessor.support(authenticationTO)) {
  46.                     UserDetails userDetails = oAuthUserProcessor.findUser(authenticationTO);
  47.                     //TODO 需要加载OpenApi用户的权限
  48.                     loadAuthorities(userDetails, authenticationTO);
  49.                     return userDetails;
  50.                 }
  51.             }
  52.         }
  53.         throw new UsernameNotFoundException("用户不存在");
  54.     }
  55.  
  56.     private void loadAuthorities(UserDetails userDetails, AuthenticationTO authenticationTO) {
  57.  
  58.     }
  59.  
  60.     @Override
  61.     public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
  62.         return null;
  63.     }
  64. }

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发