Spring oauth2 授权代码授予 - 无法到达 /oauth/authorize
Spring oauth2 authorization code grant - Impossibile to reach /oauth/authorize
我正在尝试通过授权代码流来确保我的休息 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_detailstable中的用户有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
你的代码的问题是SecurityConfiguration
:
中的这一部分
.and().formLogin().loginPage("/")
Spring 未检测到您的登录页面,因此无法将您重定向到该页面以作为用户进行身份验证。
解决方案是将其更改为:
.and().formLogin()
然后您将使用 Spring 的默认登录页面,授权代码流程应该可以正常工作。之后,您需要调试 '/'
的登录页面未被检测到的原因。
编辑:
真正的问题是 RestResponseEntityExceptionHandler.class
是一个 @ControllerAdvice
注释 class,它干扰了 ExceptionTranslationFilter
中发出的重定向。这是因为它正在捕获异常并将其抛出到前端,而不允许 ExceptionTranslationFilter
发出到登录页面的重定向。删除 RestResponseEntityExceptionHandler.class
的使用解决了问题,并且授权代码流程正常工作。
我正在尝试通过授权代码流来确保我的休息 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_detailstable中的用户有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
你的代码的问题是SecurityConfiguration
:
.and().formLogin().loginPage("/")
Spring 未检测到您的登录页面,因此无法将您重定向到该页面以作为用户进行身份验证。
解决方案是将其更改为:
.and().formLogin()
然后您将使用 Spring 的默认登录页面,授权代码流程应该可以正常工作。之后,您需要调试 '/'
的登录页面未被检测到的原因。
编辑:
真正的问题是 RestResponseEntityExceptionHandler.class
是一个 @ControllerAdvice
注释 class,它干扰了 ExceptionTranslationFilter
中发出的重定向。这是因为它正在捕获异常并将其抛出到前端,而不允许 ExceptionTranslationFilter
发出到登录页面的重定向。删除 RestResponseEntityExceptionHandler.class
的使用解决了问题,并且授权代码流程正常工作。