OAuth 2具有spring security并在重定向中设置State参数

时间:2018-04-04 12:48:53

标签: spring spring-boot spring-security oauth-2.0

我使用Spring启动Spring安全性,自定义“Filter”类使用OAuth 2身份验证调用CIAM服务器。我想明确设置或覆盖默认设置,以便我可以在Spring Security准备的重定向URL中设置自定义动态STATE参数,并将用户发送到CIAM服务器登录页面。这对我来说是微不足道的,但结果却远非如此。

目标是添加OAuth2重定向链接的自定义STATE参数,以便在身份验证完成后CIAM服务器将我重定向回我的页面时,我会收回自动包含在成功重定向链接中的STATE参数。 CIAM服务器。

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, 
proxyTargetClass = true)
@EnableOAuth2Client
@Order(3)
public class OAuth2LoginWebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
CiamOAuth2ClientFilter oAuth2CiamClientFilter;

@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
    return new InMemoryUserDetailsManager();
}



@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/**/*.css", "/**/*.png", "/**/*.gif", "/**/*.jpg", "/h2-console/**", "/css/**",
            "/img/**", "/font-awesome/**", "/fonts/**", "/js/**", "/signout","/signout/**", "/health");
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {

    httpSecurity
        .antMatcher("/**")
            .authorizeRequests()
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/backoffice/**").hasRole("ADMIN")
                .antMatchers("/api/**").hasRole("API")
                .antMatchers(/*"/", */"/login**", "/webjars/**", "/favicon.*", "/resources/**", 
                        "/auth/**", "/signin/**","css/**","js/**", "/signup/**", "/signout/", "/health", "/awsTest/login")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                    .and()
                        .exceptionHandling()
                            .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login/callback"))
                            .and()
                                .addFilterBefore(oAuth2CiamClientFilter.ciamFilter(), BasicAuthenticationFilter.class)
        .logout()
            .logoutUrl("/signout")
            .logoutSuccessUrl("/logout");
}

}

自定义过滤器类

@Configuration
public class CiamOAuth2ClientFilter {

@Autowired
AuthorizationCodeResourceDetails oauth2CiamResourceDetails;

@Autowired
CiamOAuth2ClientProperties oauth2CiamClientProperties;

@Autowired
OAuth2ClientContext oauth2ClientContext;

@Autowired
CiamPrincipalExtractor ciamPrincipalExtractor;

@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(filter);
    registration.setOrder(-100);
    registration.addInitParameter("test", "trrrrrrr");

    System.out.println("333333333333333333333333");
    System.out.println(registration);
    return registration;
}

public Filter ciamFilter() {

    System.out.println("postaeget");
    System.out.println(oauth2CiamClientProperties);
    System.out.println(" _-------------------------------: " + oauth2CiamClientProperties.getResource().getUserInfoUri());

    UserInfoTokenServices tokenService = new UserInfoTokenServices(oauth2CiamClientProperties.getResource().getUserInfoUri(), oauth2CiamResourceDetails.getClientId());
    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(oauth2CiamResourceDetails, oauth2ClientContext);
    OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("/login/callback");

    tokenService.setRestTemplate(restTemplate);
    tokenService.setPrincipalExtractor(ciamPrincipalExtractor);
    filter.setRestTemplate(restTemplate);
    filter.setTokenServices(tokenService);



    return filter;
}

}

与问题相关的应用程序yml设置文件

security:
oauth2:
client:

  clientId: ...
  clientSecret: ....
  accessTokenUri: ...
  userAuthorizationUri: ...
  useCurrentUri: false
  preEstablishedRedirectUri: https://localhost/login/callback
  clientAuthenticationScheme: query
  authenticationScheme: header
  serverLogoutUrl: ..
  postLogoutRedirectUri: https://localhost/signout
  scope:
    - openid
    - profile
    - email
    - offline_access
  state: TEST
resource:
  userInfoUri: ...
  preferTokenInfo: ...

1 个答案:

答案 0 :(得分:-1)

就我而言

我在@Configuration中的某处配置OAuth2ClientAuthenticationProcessingFilter:

private Filter ssoFilter() {
    OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter(API_LOGIN_FACEBOOK);
    OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(facebook(), oauth2ClientContext);
    AuthorizationCodeAccessTokenProvider authorizationCodeAccessTokenProviderWithUrl = new AuthorizationCodeAccessTokenProvider();
    authorizationCodeAccessTokenProviderWithUrl.setStateKeyGenerator(new StateKeyGeneratorWithRedirectUrl());
    facebookTemplate.setAccessTokenProvider(authorizationCodeAccessTokenProviderWithUrl);
    facebookFilter.setRestTemplate(facebookTemplate);
    UserInfoTokenServices tokenServices = new CheckedUserInfoTokenServices(
            facebookResource().getUserInfoUri(), facebook().getClientId(),
            facebookPrincipalExtractor, blogPreAuthenticationChecks(), blogPostAuthenticationChecks());
    tokenServices.setAuthoritiesExtractor(new FacebookAuthoritiesExtractor());
    tokenServices.setRestTemplate(facebookTemplate);
    facebookFilter.setTokenServices(tokenServices);
    facebookFilter.setAuthenticationSuccessHandler(new OAuth2AuthenticationSuccessHandler());
    return facebookFilter;
}

您可以通过以下方式访问StateKeyGeneratorWithRedirectUrl中的当前请求:

RequestContextHolder.getRequestAttributes()

因此您可以提取Referer标头,例如:

public class StateKeyGeneratorWithRedirectUrl extends DefaultStateKeyGenerator {
    private RandomValueStringGenerator generator = new RandomValueStringGenerator();

    @Override
    public String generateKey(OAuth2ProtectedResourceDetails resource) {
        HttpServletRequest currentHttpRequest = getCurrentHttpRequest();
        if (currentHttpRequest!=null){
            String referer = currentHttpRequest.getHeader("Referer");
            if (!StringUtils.isEmpty(referer)){
                return generator.generate()+","+referer;
            }
        }
        return generator.generate();
    }

    private static HttpServletRequest getCurrentHttpRequest(){
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes)requestAttributes).getRequest();
        }
        return null;
    }
}

下一步-从回调读取状态:

public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    public static final String DEFAULT = "/";

    @Override
    protected String determineTargetUrl(HttpServletRequest request,
                                        HttpServletResponse response) {

        UriComponents uriComponents = UriComponentsBuilder.newInstance()
            .query(request.getQueryString())
            .build();

        MultiValueMap<String, String> queryParams = uriComponents.getQueryParams();
        String stateEncoded = queryParams.getFirst("state");
        if (stateEncoded == null) {
            return DEFAULT;
        }
        String stateDecoded = URLDecoder.decode(stateEncoded, StandardCharsets.UTF_8);
        String[] split = stateDecoded.split(",");
        String redirect;
        if (split.length != 2){
            return DEFAULT;
        } else {
            return split[1];
        }
    }
}