1. 程式人生 > >spring security OAuth2.0之客戶端Client的實現

spring security OAuth2.0之客戶端Client的實現

ner hub context uestc tap tde val pos ise

項目代碼: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();
}

大功告成!

spring security OAuth2.0之客戶端Client的實現