• Gateway + Oauth2实现单点登录


    首先引入pom依赖

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

    1. <dependencies>
    2. <dependency>
    3. <groupId>io.github.resilience4jgroupId>
    4. <artifactId>resilience4j-feignartifactId>
    5. <version>1.1.0version>
    6. dependency>
    7. <dependency>
    8. <groupId>org.springframework.bootgroupId>
    9. <artifactId>spring-boot-starterartifactId>
    10. dependency>
    11. <dependency>
    12. <groupId>org.springframework.bootgroupId>
    13. <artifactId>spring-boot-starter-testartifactId>
    14. <scope>testscope>
    15. dependency>
    16. <dependency>
    17. <groupId>org.springframework.cloudgroupId>
    18. <artifactId>spring-cloud-starter-gatewayartifactId>
    19. dependency>
    20. <dependency>
    21. <groupId>org.springframework.cloudgroupId>
    22. <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    23. <version>2.2.2.RELEASEversion>
    24. dependency>
    25. <dependency>
    26. <groupId>org.projectlombokgroupId>
    27. <artifactId>lombokartifactId>
    28. <optional>trueoptional>
    29. dependency>
    30. <dependency>
    31. <groupId>org.springframework.bootgroupId>
    32. <artifactId>spring-boot-starter-actuatorartifactId>
    33. dependency>
    34. 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 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 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.cloudgroupId>
    4.            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
    5.            <version>2.2.2.RELEASEversion>
    6.        dependency>
    7.  
    8.        <dependency>
    9.            <groupId>org.springframework.bootgroupId>
    10.            <artifactId>spring-boot-starter-webartifactId>
    11.        dependency>
    12.  
    13.        <dependency>
    14.            <groupId>org.springframework.bootgroupId>
    15.            <artifactId>spring-boot-starter-data-redisartifactId>
    16.        dependency>
    17.  
    18.        <dependency>
    19.            <groupId>org.mybatis.spring.bootgroupId>
    20.            <artifactId>mybatis-spring-boot-starterartifactId>
    21.            <version>2.1.1version>
    22.        dependency>
    23.       <dependency>
    24.            <groupId>com.alibabagroupId>
    25.            <artifactId>druidartifactId>
    26.            <version>1.1.21version>
    27.        dependency>
    28.  
    29.        <dependency>
    30.            <groupId>mysqlgroupId>
    31.            <artifactId>mysql-connector-javaartifactId>
    32.            <version>8.0.18version>
    33.        dependency>
    34.  
    35.     
    36.        <dependency>
    37.            <groupId>org.springframework.cloudgroupId>
    38.            <artifactId>spring-cloud-starter-oauth2artifactId>
    39.            <version>2.2.0.RELEASEversion>
    40.        dependency>
    41.        <dependency>
    42.            <groupId>org.springframework.cloudgroupId>
    43.            <artifactId>spring-cloud-starter-securityartifactId>
    44.            <version>2.2.0.RELEASEversion>
    45.        dependency>
    46.  
    47.        <dependency>
    48.            <groupId>org.springframework.securitygroupId>
    49.            <artifactId>spring-security-oauth2-joseartifactId>
    50.            <version>5.2.2.RELEASEversion>
    51.        dependency>
    52.        <dependency>
    53.            <groupId>org.springframework.cloudgroupId>
    54.            <artifactId>spring-cloud-starter-openfeignartifactId>
    55.            <version>2.2.2.RELEASEversion>
    56.        dependency>
    57.        <dependency>
    58.            <groupId>io.github.openfeigngroupId>
    59.            <artifactId>feign-okhttpartifactId>
    60.            <version>10.9version>
    61.        dependency>
    62.  
    63.        <dependency>
    64.            <groupId>org.projectlombokgroupId>
    65.            <artifactId>lombokartifactId>
    66.            <optional>trueoptional>
    67.        dependency>
    68.  
    69.    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 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 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. }

  • 相关阅读:
    azkaban表project_flows数据分析
    扒开源安卓性能测试工具moblieperf源码——开发属于你自己的性能稳定性测试工具
    H3CNE综合小实验
    Timeline的使用心得
    森林防火与林业资源综合解决方案
    如何将PDF文件转换成Excel呢?
    络达开发---自定义BLE服务(二):功能实现
    如何将两台Mac显示器设置为单个屏幕配置
    代码随想录算法训练营第四十九天|139.单词拆分
    Quantlab5.0:一切围绕可实盘策略驱动开发
  • 原文地址:https://blog.csdn.net/fivehundredyearsago/article/details/126000293