Spring OAuth2-/ oauth / authorize-用户必须通过身份验证错误

时间:2019-05-28 11:21:49

标签: spring spring-security spring-security-oauth2

我正在尝试使用authorization_code流保护我的其余api。我有一个资源服务器和一个单独的授权服务器。我使用授权服务器的oauth / token端点生成用户令牌,并使用此令牌访问资源服务器,该资源服务器在内部调用授权服务器的/ oauth / authorize端点。但是,当调用授权端点时,会给出错误

  

org.springframework.security.authentication.InsufficientAuthenticationException:必须先通过Spring Security对用户进行身份验证,然后才能完成授权。

下面是配置

授权服务器

WebSecurity

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin().disable()//
            .csrf().disable() //
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
            .and().exceptionHandling() //
                .authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)) //
            .and().requestMatchers().antMatchers("/login") //
            .and().authorizeRequests()
                .antMatchers("/login").permitAll() //
                .anyRequest().authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Bean
    public AuthenticationKeyGenerator authenticationKeyGenerator() {
        return new DefaultAuthenticationKeyGenerator();
    }

    @Bean
    public ClientKeyGenerator clientKeyGenerator() {
        return new DefaultClientKeyGenerator();
    }

}

AuthorizationServer

@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private MyTokenStore myTokenStore;

    @Autowired
    private MyClientDetailsService myClientDetailsService;

    @Autowired
    private MyApprovalStore myApprovalStore;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(myClientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
        endpoints.tokenStore(myTokenStore) //
                .tokenEnhancer(tokenEnhancerChain) //
                .approvalStore(myApprovalStore) //
                .authenticationManager(authenticationManager);
    }

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new MyTokenEnhancer();
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "123456".toCharArray());
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("123456"));
        return converter;
    }

    @Configuration
    protected static class GlobalAuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {

        @Autowired
        private UserDetailsService userDetailsService;

        @Autowired
        private PasswordEncoder passwordEncoder;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
        }

    }
}

ResourceServer

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Autowired
    private MyTokenStore myTokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable() //
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
                .and().authorizeRequests() //
                .antMatchers("/login").permitAll() //
                .anyRequest().authenticated();
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("public.cert");
        String publicKey = null;
        try {
            publicKey = IOUtils.toString(resource.getInputStream(), StandardCharsets.UTF_8);
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
        converter.setVerifierKey(publicKey);
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenEnhancer(accessTokenConverter());
        defaultTokenServices.setTokenStore(myTokenStore);
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }

}

资源服务器(客户端)

WebSecurity

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests() //
                .antMatchers("/", "/login**").permitAll() //
                .anyRequest().authenticated() //
                .and().oauth2Login();
    }

}

application.yml

spring:
  security:
    oauth2:
      client:
        registration:
          custom-auth:
            client-name: custom-auth
            client-id: org1
            client-secret: 123456
            scope: openid
            provider: custom-auth
            redirect-uri: http://localhost:8080/login/oauth2/code/
            authorization-grant-type: authorization_code
        provider:
          custom-auth:
            token-uri: http://localhost:8180/oauth/token
            authorization-uri: http://localhost:8180/oauth/authorize
            user-info-uri: http://localhost:8180/user/me

我已经看到将oauth / authorize请求发送到授权服务器,并且承载令牌包含在请求中。

这是一个基于完全休息的API,我没有任何页面。

已编辑

我一直在寻找春天,发现为内部调用OAuth2AuthenticationProcessingFilter的资源调用了FilterChainProxy,并将Authentication对象设置为RequestContext。但是对于/ oauth / authorize,我看不到FilterChainProxy被调用,反正我可以让FilterChainProxy用于/ oauth / authorize。

0 个答案:

没有答案