我正在尝试使用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。