【问题标题】:Spring oauth2 authorization code grant - Impossibile to reach /oauth/authorizeSpring oauth2 授权码授予 - 无法到达 /oauth/authorize
【发布时间】:2017-08-31 16:37:00
【问题描述】:

我正在尝试使用授权代码流来保护我的 rest api,但我不明白为什么我会收到该消息:

User must be authenticated with Spring Security before authorization can be completed.

我有一个具有用户和管理员访问权限的应用程序 Web 部分,以及一个具有 2 个不同授权的 REST api 部分,在 /api/** 授权代码和 /oauth2/** 上带有 client_credentials。

client_credential 流程有效,但授权码不行...

所以,这是我的授权服务器配置

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    DataSource dataSource;

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

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints.tokenStore(tokenStore()).authenticationManager(authManager);

    }

    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

}

这是我的资源服务器配置

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    DataSource dataSource;

     @Override
        public void configure(HttpSecurity http) throws Exception {

           http
    .requestMatchers()
    .antMatchers("/api/**")
    .antMatchers("/oauth2/**")
    .and().authorizeRequests()
    .antMatchers("/api/**").access("hasRole('USER')")
    .antMatchers("/oauth2/**").authenticated()
    .and().httpBasic();
        }

     @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

     @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {

            resources.tokenStore(tokenStore());
        }
}

最后,这是一般的安全性

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("customUserDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    CustomSuccessHandler customSuccessHandler;

    @Autowired
    CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    DataSource dataSource;

    @Autowired
    public void configureGlobalService(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());

    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

        http.authorizeRequests()

                .antMatchers("/", "/registration", "/registrationConfirm", "/resendRegistrationToken")
                .permitAll()

                .antMatchers("/edit/**", "/payment/**", "/plate/**", "/book/**", "/home", "/stop/**",
                        "/notification/**", "/include/**")
                .access("hasRole('USER') or hasRole('ADMIN') or hasRole('PARK')").antMatchers("/admin/**")
                .access("hasRole('ADMIN') or hasRole('PARK')").antMatchers("/updatePassword")
                .hasAuthority("CHANGE_PASSWORD_PRIVILEGE")

                .and().formLogin().loginPage("/")
                .successHandler(customSuccessHandler).failureHandler(customAuthenticationFailureHandler)
                .usernameParameter("email").passwordParameter("password").and().rememberMe()
                .rememberMeParameter("remember-me").tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(86400).and().exceptionHandling().accessDeniedPage("/Access_Denied").and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/?logout=true").invalidateHttpSession(false).deleteCookies("JSESSIONID");

        http.csrf().disable();

    }

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

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
        db.setDataSource(dataSource);
        return db;
    }

}

oauth_client_details表中的用户有ROLE_USER作为权限,client_id和client_secret是test/test

这就是我正在寻找使用 POSTMAN 获取令牌的方式

但我遇到了异常

ERROR i.b.e.e.RestResponseEntityExceptionHandler[66] - 500 Status Code org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.

编辑这是我按下请求令牌按钮时看到的

编辑 检查日志,我还发现在我的安全过滤器链中没有任何 Oauth2 过滤器的迹象......当我请求获取授权令牌时,我看到:

2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 5 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 8 of 12 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[325] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman.com%2Foauth2%2Fcallback&response_type=code at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-04-07 22:50:34 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy[310] - /oauth/authorize?client_id=test&scope=&state=7220832&redirect_uri=https%3A%2F%2Fwww.getpostman

【问题讨论】:

  • 按“请求访问令牌”时是否看到登录页面?
  • 不,我会遇到 500 错误和我的书呆子身份验证的混乱

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


【解决方案1】:

你的代码的问题是SecurityConfiguration里面的这个部分:

.and().formLogin().loginPage("/")

Spring 没有检测到您的登录页面,因此您无法被重定向到以用户身份对其进行身份验证。

解决方案是将其更改为:

.and().formLogin()

然后您将使用 Spring 的默认登录页面,并且授权代码流程应该可以工作。之后,您需要调试为什么没有检测到您在'/' 的登录页面。

编辑:

真正的问题是RestResponseEntityExceptionHandler.class 是一个@ControllerAdvice 注释类,它与ExceptionTranslationFilter 中发出的重定向混淆。这是因为它正在捕获异常并将其抛出到前端,而不允许ExceptionTranslationFilter 发出重定向到登录页面。删除 RestResponseEntityExceptionHandler.class 的使用解决了问题,并且 Auth 代码流正常工作。

【讨论】:

  • 没什么改变...我应该有 2 个用于 Web 应用程序的登录入口点 loginPage("/") 和用于 Oauth 身份验证的标准 Spring 登录
  • 如果您指定loginPage("/"),您将无法在春季访问默认登录页面...见docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/guides/…
  • 试图...但我在尝试访问 /oauth/authorize 时继续收到User must be authenticated with Spring Security before authorization can be 我可以登录应用程序 Web 部分的标准 Spring 登录页面......问题在于它的 REST 部分
  • 那么在按下'Request Token'后,通过Spring生成的页面登录,然后报错?
  • 不,当我按下它时,我没有得到登录页面,我在原始问题中添加了图像
猜你喜欢
  • 2017-01-10
  • 2018-05-26
  • 1970-01-01
  • 1970-01-01
  • 2012-05-31
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
  • 2018-01-12
相关资源
最近更新 更多