Spring Boot 2.0 & OAuth 2.0 客户端实现

在oauth2.0框架中,主要包含了三个角色,授权端,客户端,资源端。
授权端指的是oauth2.0的授权服务,客户端可能是浏览器,也可能是java服务,资源端是给客户端提供资源服务的.
从流程上看,客户端提供认证信息,从授权服务获取令牌,让拿着令牌到资源服务获取内容,资源服务会拿着客户端给的令牌去授权服务校验令牌的有效性,无问题则返回相应资源。

单论客户端而言,首先需要配置授权必须的配置,比如clientid,clientSecret等。

配置模板如下

    client:
      clientId: spring-security-oauth2-read-client  
      clientSecret: spring-security-oauth2-read-client-password1234
      accessTokenUri: http://localhost:8080/oauth/token 
      userAuthorizationUri: http://localhost:8080/oauth/authorize 
      clientAuthenticationScheme: form
      authenticationScheme: query

    resource:
      userInfoUri: http://localhost:8080/secured/user

然后需要实现登入功能,需要跳转到收取按服务的登入页面获取令牌。

具体的写个类实现继承WebSecurityConfigurerAdapter。
在这里我们需要重写下void configure(HttpSecurity http),主要配置下那些接口需要认证,那些不需要,登入成功后跳转哪个页面,添加认证过滤器等。
具体的可以查看下HttpSecurity的用法。

   @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**", "/error**").permitAll().anyRequest()
                .authenticated().and().exceptionHandling()
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout()
                .logoutSuccessUrl("/").permitAll().and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
        // @formatter:on
    }

接下来,需要实现一个客户端认证的过滤器,并加载之前写的配置信息。
首先声明一个配置类,包装了配置过滤器需要的参数。

class ClientResources {

    @NestedConfigurationProperty
    private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();

    @NestedConfigurationProperty
    private ResourceServerProperties resource = new ResourceServerProperties();

    public AuthorizationCodeResourceDetails getClient() {
        return client;
    }

    public ResourceServerProperties getResource() {
        return resource;
    }
}

再写个创建bean的方法。

    @Bean
    @ConfigurationProperties("client")
    public ClientResources github() {
        return new ClientResources();
    }



接下来,我们调用这个配置好的bean创建过滤器。

    private Filter ssoFilter() {
        CompositeFilter filter = new CompositeFilter();
        List filters = new ArrayList<>();
        filters.add(ssoFilter(github(), "/login/github"));
        filter.setFilters(filters);
        return filter;
    }

    private Filter ssoFilter(ClientResources client, String path) {
        OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
        OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
        oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
        UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
                client.getClient().getClientId());
        tokenServices.setRestTemplate(oAuth2RestTemplate);
        oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
        return oAuth2ClientAuthenticationFilter;
    }

这个时候基本配置完毕,能够调用认证服务登入了。