【问题标题】:OAuth 2 with spring security and setting the State parameter in the redirect具有弹簧安全性的 OAuth 2 并在重定向中设置 State 参数
【发布时间】:2018-09-14 01:02:36
【问题描述】:

我正在使用带有 Spring 安全性的 Spring Boot,自定义“过滤器”类通过 OAuth 2 身份验证调用 CIAM 服务器。我想显式设置或覆盖默认设置,以便我可以在 Spring Security 在后台准备的重定向 URL 中设置自定义动态状态参数,并将用户发送到 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: ...

【问题讨论】:

    标签: spring spring-boot spring-security oauth-2.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];
            }
        }
    }
    

    【讨论】:

    • 请使用正确的代码样式,并详细说明您的答案。
    • 非常感谢 Nikita。我一直在努力寻找一种框架支持方式来发送要重定向的深层链接以及“状态”参数。谢谢
    猜你喜欢
    • 2012-03-12
    • 2014-03-06
    • 2014-02-09
    • 2016-09-29
    • 1970-01-01
    • 2019-10-07
    • 2015-09-04
    • 1970-01-01
    • 2013-04-12
    相关资源
    最近更新 更多