• spring security OAuth2.0之客户端Client的实现


    项目代码:https://github.com/hankuikuide/microservice-spring-security-oauth2

    网上多数的项目客户端都是采用纯js写,或用postman发请求,和实际项目的应用还是有差距的,这里也是采用spring boot的实现。 主要功能在于:

    • 使用授权码模式进行认证。
    • 使用OAuth2RestTemplate发送请求给认证服务器和资源服务器,
    • 结合Feign实现loadbalance.

    先进行security的配置:

    @Configuration
    @EnableOAuth2Sso
    public class UiSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter;
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/**")
                    .authorizeRequests()
                    .antMatchers("/", "/login**")
                    .permitAll().anyRequest().authenticated()
                    .and()
                    .addFilterBefore(oauth2ClientAuthenticationProcessingFilter,BasicAuthenticationFilter.class)
                    .csrf().disable();
    
        }
    
    }

    在BasicAuthenticationFilter之前添加了一个过滤器。

    客户端中最关键的代码,如下:

    核心功能是

    1. 注册OAuth2RestTemplate,

    2.注册处理redirect uri的filter.也就是上面说的过滤器。

    3. 注册check token服务

    有了这个类,使用授权码模式,就可以把登录成功后的授权码接收到,并自动发给认证服务器请求token,并在后续的请求中自动添加token了。

    @Configuration
    public class Oauth2ClientConfig {
    
        private  String redirectUri ="http://localhost:9001/login";
        private  String checkTokenUrl ="http://localhost:9002/auth/oauth/check_token";
    
        @Bean
        public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) {
            OAuth2RestTemplate template = new OAuth2RestTemplate(details, context);
    
            AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider();
            authCodeProvider.setStateMandatory(false);
            AccessTokenProviderChain provider = new AccessTokenProviderChain(
                    Arrays.asList(authCodeProvider));
            template.setAccessTokenProvider(provider);
    
            return template;
        }
    
        /**
         * 注册处理redirect uri的filter
         * @param oauth2RestTemplate
         * @param tokenService
         * @return
         */
        @Bean
        public OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter(
                OAuth2RestTemplate oauth2RestTemplate,
                RemoteTokenServices tokenService) {
            OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(redirectUri);
            filter.setRestTemplate(oauth2RestTemplate);
            filter.setTokenServices(tokenService);
    
    
            //设置回调成功的页面
            filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    this.setDefaultTargetUrl("/home");
                    super.onAuthenticationSuccess(request, response, authentication);
                }
            });
            return filter;
        }
        /**
         * 注册check token服务
         * @param details
         * @return
         */
        @Bean
        public RemoteTokenServices tokenService(OAuth2ProtectedResourceDetails details) {
            RemoteTokenServices tokenService = new RemoteTokenServices();
            tokenService.setCheckTokenEndpointUrl(checkTokenUrl);
            tokenService.setClientId(details.getClientId());
            tokenService.setClientSecret(details.getClientSecret());
            return tokenService;
        }
    }

    再有虽然我们这里配置了OAuth2RestTemplate,但是通过为了实现loadbalance,通过我们会使用FeignClient,介绍一下如何将二者结合使用。

    为了使用@EnableFeignClients

    首先引入依赖管理:

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            </dependency>

    启用FeignClient

    @SpringBootApplication
    @EnableFeignClients
    public class ClientApplication {
        @Bean
        public RequestContextListener requestContextListener() {
            return new RequestContextListener();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(ClientApplication.class, args);
        }
    
    }

    重要的配置来了:配置请求拦截器,并注入OAuth2RestTemplate

    @Configuration
    public class OAuth2FeignAutoConfiguration {
    
        @Bean
        public RequestInterceptor oauth2FeignRequestInterceptor( OAuth2RestTemplate oAuth2RestTemplate) {
            return new OAuth2FeignRequestInterceptor(oAuth2RestTemplate);
        }
    }

    实现这个拦截器:代码很简单就是把OAuth2RestTemplate 的token取出来放在restTemplate的header上,

    public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
    
    
        private static final String AUTHORIZATION_HEADER = "Authorization";
    
        private static final String BEARER_TOKEN_TYPE = "Bearer";
    
        private final OAuth2RestTemplate oAuth2RestTemplate;
    
    
        public OAuth2FeignRequestInterceptor(OAuth2RestTemplate oAuth2RestTemplate) {
            this.oAuth2RestTemplate = oAuth2RestTemplate;
        }
    
        @Override
        public void apply(RequestTemplate template) {
            System.out.println("Constructing Header "+AUTHORIZATION_HEADER+" for Token " + BEARER_TOKEN_TYPE +":" +oAuth2RestTemplate.getAccessToken().toString());
            template.header(AUTHORIZATION_HEADER,
                    String.format("%s %s",
                            BEARER_TOKEN_TYPE,
                            oAuth2RestTemplate.getAccessToken().toString()));
    
        }
    }

    定义服务接口

    @FeignClient(name = "resource-service", url = "http://localhost:9003/auth", fallback = ResourceServiceFallback.class )
    public interface ResourceService {
    
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
        String hello();
    }

    大功告成!

  • 相关阅读:
    php数组转换成js可用的数组的两种方式
    常用正则表达式--------------[拿把小刀,强大自己]
    AngularJs 相应回车事件
    常见的关系型数据库和非关系型数据库及其区别
    CMDB资产采集
    GB和GiB的区别
    python枚举详解
    python保留两位小数
    详解TCP三握四挥
    npm run dev 和 npm run serve
  • 原文地址:https://www.cnblogs.com/hankuikui/p/10879641.html
Copyright © 2020-2023  润新知